Open Source

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

iOS Safari 17.4+

Switch Checkbox Exploit

Toggles a hidden <input type="checkbox" switch> element to trigger Safari's built-in haptic feedback.

Android Chrome

PWM Vibration

Converts intensity values into rapid on/off pulse-width modulation patterns via navigator.vibrate().

Desktop

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.

Tap a preset below

Getting Started

1

Install

Add the package to your project.

bun add github:doublej/web-haptics-polyfill
2

Import

Use the default singleton or create a custom instance.

import { haptics } from 'web-haptics-polyfill'
3

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>