web-haptics-polyfill
Cross-platform haptic feedback for mobile web apps. Real haptics on iOS Safari, vibration with intensity control on Android, and an audio fallback for desktop.
How It Works
Switch Checkbox Exploit
Toggles a hidden <input type="checkbox" switch> element to trigger Safari's built-in haptic feedback.
PWM Vibration
Converts intensity values into rapid on/off pulse-width modulation patterns via navigator.vibrate().
Audio Engine
Plays bandpass-filtered white noise bursts through AudioContext so you can feel the patterns while developing.
Features
iOS Safari Haptics
Real haptic feedback on iPhone via the hidden <input switch> checkbox exploit — no native app required.
Android PWM Vibration
Variable intensity on Android using pulse-width modulation patterns through navigator.vibrate().
Audio Fallback
Bandpass-filtered white noise bursts through AudioContext for desktop development and testing.
Framework Bindings
First-class hooks for React, Svelte, and Vue with automatic cleanup on unmount.
Preset Patterns
11 built-in haptic presets — success, error, warning, selection, light, medium, heavy, and more.
Zero Dependencies
Tiny footprint with no runtime dependencies. Tree-shakeable ESM and CJS builds.
Try It
Tap a preset to trigger it. Real haptics on mobile, audio feedback on desktop.
Getting Started
Install
Add the package to your project.
bun add github:doublej/web-haptics-polyfillImport
Use the default singleton or create a custom instance.
import { haptics } from 'web-haptics-polyfill'Trigger
Fire haptic feedback with a preset name, duration, or custom pattern.
haptics.trigger('success')
haptics.trigger(100)
haptics.trigger([{ duration: 30, intensity: 0.5 }])Framework Integrations
React
import { useHaptics } from 'web-haptics-polyfill/react'
function Button() {
const { trigger } = useHaptics()
return <button onClick={() => trigger('success')}>Tap</button>
}Svelte
<!-- script -->
import { createHaptics } from 'web-haptics-polyfill/svelte'
const { trigger } = createHaptics()
<!-- template -->
<button onclick={() => trigger("success")}>Tap</button>Vue
<!-- script setup -->
import { useHaptics } from 'web-haptics-polyfill/vue'
const { trigger } = useHaptics()
<!-- template -->
<button @click="trigger('success')">Tap</button>