Activity
#6096·Dennis Hackethal revised 2 days agoweb-haptics: Haptic Feedback Finally Comes to iOS Safari
Photo by Andrew Kliatskyi on Unsplash
lochie just published a package bringing haptic feedback to the web on iOS: web-haptics. I spent four years at Apple working mostly on UIs, so I pay close attention to design and UX. In terms of presentation, use case, and attention to detail, this package comes as close to perfect as I’ve seen.
The problem
On Android, haptics have been available through
navigator.vibrate(), but iOS does not support this API. There is a workaround, though – theinputelement with theswitchattribute:html<input type="checkbox" switch>See this switch input in action here. On iOS, the input renders not as a regular checkbox but as a switch that can be toggled on or off:
Open the link on your iPhone, tap the switch, and you’ll feel haptic feedback. As far as I know, this is currently the only known practical workaround to trigger haptic feedback on the web in iOS.
Implementation
lochie cleverly bases his package on this single workaround and pushes it to its limits. The key lines are here, creating a switch input on the fly:
js (rendered as javascript)const hapticCheckbox = document.createElement("input");hapticCheckbox.type = "checkbox";hapticCheckbox.setAttribute("switch", "");The package also creates an associated label and clicks it to trigger haptic feedback on the connected input:
js (rendered as javascript)this.hapticLabel.click();(My understanding is that iOS will not trigger the haptic feedback when the input is programmatically clicked – so the ‘workaround within the workaround’ is to click the associated label instead.)
Custom haptics (!)
But web-haptics can do more than just trigger a single haptic ‘pulse’. The
triggerfunction lets you pass in your own patterns with pulses of different duration and intensity, and even delays.Want a simple success haptic? Trigger two pulses, as shown on the package homepage:
js (rendered as javascript)trigger([{ duration: 30 },{ delay: 60, duration: 40, intensity: 1 },])Or simply call
trigger('success')as a shortcut.Here’s an error haptic I made based on Apple’s human interface guidelines:
js (rendered as javascript)trigger([{ duration: 40, intensity: 0.7 },{ delay: 40, duration: 40, intensity: 0.7 },{ delay: 40, duration: 40, intensity: 0.9 },{ delay: 40, duration: 50, intensity: 0.6 },])lochie’s website even gives you an editor to make custom haptics. As you click and drag, both pulses and code update in real time. This experience is developer bliss:
Usage
Importing the package is easy. In Rails, for example:
rb (rendered as ruby)# config/importmap.rbpin "web-haptics", to: "https://esm.sh/web-haptics@0.0.6"js (rendered as javascript)import { WebHaptics } from 'web-haptics';// In a Stimulus controller somewherelet haptics = new WebHaptics();haptics.trigger('success'); // or 'error', 'warning', etc for built-in hapticshaptics.trigger([{ duration: 40, intensity: 0.7 },{ delay: 40, duration: 40, intensity: 0.7 },])Pass a
debugoption to the constructor to hear clicks in development/on desktop:js (rendered as javascript)new WebHaptics({ debug: true });Again, this package comes as close to perfect as I’ve seen. In fact, I already use it on Veritula: as you type in a text field, an error haptic plays when you exceed the max length (#4473).
I highly recommend web-haptics by lochie.
Comes to iOS Safari
Sadly, as of a recent iOS update, Apple removed the ability to trigger haptic feedback in Webkit browsers.
Should still work on Android, though.

