Add haptic feedback to web apps using the web-haptics library. Use when building mobile-facing UIs that need tactile feedback on buttons, toggles, forms, pickers, and other interactive elements.
Install web-haptics (npm i web-haptics) and add haptic feedback to the app following these rules:
Repository: https://github.com/lochie/web-haptics | License: MIT | Zero dependencies Uses the Web Vibration API. Silently no-ops on unsupported platforms (desktop). No error handling or feature detection needed.
trigger() accepts one of these strings (empty value defaults to a sensible "medium" impact):
Notification (task outcomes):
Impact (physical collisions):
Selection (discrete stepping):
React:
import { useWebHaptics } from "web-haptics/react";
const haptic = useWebHaptics();
<button onClick={() => haptic.trigger()}>Tap me</button>;
Vue:
<script setup>
import { useWebHaptics } from "web-haptics/vue";
const haptic = useWebHaptics();
</script>
<template>
<button @click="haptic.trigger()">Tap me</button>
</template>
Svelte:
<script>
import { createWebHaptics } from "web-haptics/svelte";
import { onDestroy } from "svelte";
const haptic = createWebHaptics();
onDestroy(() => haptic.destroy());
</script>
<button on:click={() => haptic.trigger()}>Tap me</button>
Vanilla JS:
import { WebHaptics } from "web-haptics";
const haptics = new WebHaptics();
haptics.trigger(); // medium impact
haptics.trigger("success");
Next.js: add "use client" to any component using useWebHaptics(). Nuxt/SvelteKit: works directly, library handles SSR.
All named string presets have a corresponding object in defaultPatterns. Use when you need to pass a preset as a value rather than a string literal:
import { WebHaptics, defaultPatterns } from "web-haptics";
const haptics = new WebHaptics();
haptics.trigger(defaultPatterns.light);
Extra presets not listed above: "soft", "rigid", "nudge", "buzz". See defaultPatterns for all available values.
try {
await submit();
haptic.trigger("success");
} catch {
haptic.trigger("error");
}
Primary button tap = "medium" | Secondary button = "light" Form success = "success" | Validation error = "error" | Network error = "error" Toggle switch = "light" | Delete before confirm = "warning" Picker/wheel = "selection" | Slider detents = "selection" | Tab switch = "selection" Drag-drop snap = "medium" | Long press = "heavy" | Modal appear = "medium" Pull-to-refresh threshold = "light" | Swipe dismiss threshold = "light" Payment confirmed = "success"