A Svelte attachment for adding haptic feedback to elements using the Svelte 5 attachments API.
Uses the Web Vibration API. Silently no-ops on unsupported platforms (desktop).
npm install svelte-attach-haptic
<script lang="ts">
import { haptic, useHaptic } from "svelte-attach-haptic";
const tap = useHaptic("medium", ["pointerdown"]);
</script>
<!-- Default: medium intensity on click -->
<button {@attach haptic()}>Default</button>
<!-- Built-in presets -->
<button {@attach haptic({ pattern: "success" })}>Success</button>
<button {@attach haptic({ pattern: "error" })}>Error</button>
<!-- Custom event trigger -->
<button {@attach haptic({ pattern: "heavy", events: ["pointerdown"] })}>Heavy on pointerdown</button>
<!-- Factory: create a reusable haptic with shared defaults -->
<button {@attach tap()}>Factory default</button>
<button {@attach tap({ pattern: "light" })}>Factory with override</button>
haptic(options?)Svelte attachment that triggers haptic feedback on an element.
| Option | Type | Default | Description |
|---|---|---|---|
pattern |
HapticInput |
"medium" |
Vibration pattern or preset name |
events |
[triggerEvent, cancelEvent?] |
["click"] |
DOM events to trigger/cancel haptics |
intensity |
number |
0.5 |
Global intensity override (0–1) |
useHaptic(pattern?, events?, intensity?)Factory function that returns a reusable attachment with preset defaults. The returned function accepts optional overrides per element.
<script lang="ts">
import { useHaptic } from "svelte-attach-haptic";
const tap = useHaptic("medium", ["pointerdown"]);
</script>
<button {@attach tap()}>Uses defaults</button>
<button {@attach tap({ pattern: "light" })}>Override pattern</button>
Haptic classFor manual control outside of attachments:
import { Haptic } from "svelte-attach-haptic";
const h = new Haptic("success");
h.trigger();
h.cancel();
isSupportedBoolean indicating whether the Web Vibration API is available.
| Preset | Category | Description |
|---|---|---|
"light" |
Impact | Short, subtle tap (small toggle, minor interaction) |
"medium" |
Impact | Standard tap (button press, card snap-to-position) |
"heavy" |
Impact | Strong impact (major state change, force press) |
"soft" |
Impact | Soft impact (gentle interaction) |
"rigid" |
Impact | Crisp impact (sharp, precise feedback) |
"selection" |
Selection | Selection feedback (picker scroll, slider detent) |
"success" |
Notification | Success notification (form saved, payment confirmed) |
"warning" |
Notification | Warning notification (destructive action, limit reached) |
"error" |
Notification | Error notification (validation failure, network error) |
"nudge" |
Other | Double bump (attention grab) |
"buzz" |
Other | Long buzz |
// Single duration (ms)
haptic({ pattern: 200 });
// Array of durations (vibrate, pause, vibrate, ...)
haptic({ pattern: [100, 50, 100] });
// Vibration objects with per-step intensity
haptic({
pattern: [
{ duration: 50, intensity: 0.8 },
{ delay: 100, duration: 30, intensity: 0.4 },
],
});
"light"/"selection". Standard → "medium"/"success". Major → "heavy"/"error"/"warning".try {
await submit();
new Haptic("success").trigger();
} catch {
new Haptic("error").trigger();
}