4 min read
0%

Haptic Feedback API

Back to Blog
Haptic Feedback API

Haptic Feedback API (Vibration)

The Vibration API lets you trigger haptic feedback on mobile devices with a single method call. It’s been shipping in Android browsers for years and is a reliable progressive enhancement for touch-heavy UIs.

// Single pulse: 200ms vibration
navigator.vibrate(200);

// Pattern: vibrate 100ms, pause 50ms, vibrate 100ms
navigator.vibrate([100, 50, 100]);

// Cancel any running vibration
navigator.vibrate(0);

Feature Detection

if ("vibrate" in navigator) {
  navigator.vibrate(50);
}

Always guard with a feature check. The API returns false on desktop or when vibration is blocked by the user agent — it never throws.

Patterns for Common Interactions

Define a small set of named haptic patterns and reuse them across the app:

const haptics = {
  tap: () => navigator.vibrate(10),
  confirm: () => navigator.vibrate([20, 30, 20]),
  error: () => navigator.vibrate([50, 20, 50, 20, 50]),
  success: () => navigator.vibrate([10, 40, 80]),
};

// Wire up to interactions
button.addEventListener("click", () => {
  haptics.tap();
  doThing();
});

Short pulses (10–30ms) feel like a tap; longer ones (50–100ms) feel like a thud. Patterns with multiple pulses communicate sequences — useful for errors or confirmations.

Accessibility Considerations

Some users are sensitive to unexpected vibration. Follow these guidelines:

  • Tie vibration to explicit user actions (tap, press, swipe) — never trigger autonomously
  • Respect prefers-reduced-motion as a signal that the user may want less sensory feedback
  • Provide a UI toggle to disable haptics and persist the preference
const prefersReduced = matchMedia("(prefers-reduced-motion: reduce)").matches;

function vibrate(pattern) {
  if (!prefersReduced && "vibrate" in navigator) {
    navigator.vibrate(pattern);
  }
}

Combining with Pointer Events

Haptics sync naturally with pointer events for drag interactions:

let dragging = false;

element.addEventListener("pointerdown", () => {
  dragging = true;
  navigator.vibrate(15); // grab feedback
});

element.addEventListener("pointerup", () => {
  if (dragging) {
    navigator.vibrate([10, 20, 10]); // release feedback
    dragging = false;
  }
});

Limitations

  • iOS Safari: Apple does not expose the Vibration API. Use the taptic engine via native APIs in PWAs with WKWebView — not available from web content.
  • Duration cap: Some browsers cap maximum vibration duration per pulse (usually 10 seconds). Patterns are also subject to total duration limits.
  • Background tab: Vibration is suppressed when the page is not visible.
  • User gesture requirement: Chrome requires a user gesture on the page before vibration is allowed.

PWA Usage

For installable PWAs, haptics meaningfully close the gap with native apps. Wire them up to swipe-to-dismiss, pull-to-refresh, and long-press menus:

// Long-press context menu
let longPressTimer;

element.addEventListener("pointerdown", () => {
  longPressTimer = setTimeout(() => {
    navigator.vibrate(30);
    showContextMenu();
  }, 500);
});

element.addEventListener("pointerup", () => {
  clearTimeout(longPressTimer);
});

Browser support snapshot

Live support matrix for vibration from Can I Use.

Show static fallback image Data on support for vibration across major browsers from caniuse.com

Source: caniuse.com

Canvas is not supported in your browser