Haptics

The tactile third of seam's touch-feedback pillar. Mount one provider and every control clicks and buzzes as you use it — the same feel as this site.

Tap a key — it springs and clicks. On a phone it buzzes too (Android Vibration API / iOS taptic). Mount <HapticsProvider> once and every seamui control does this; enabled and sound are the runtime knobs.

bunx --bun seamui@latest add haptics

Usage

import { HapticsProvider } from "@/lib/haptics"

// once, around your app shell:
<HapticsProvider>
  <App />
</HapticsProvider>

That's it — Button, Toggle (and everything dogfooding them, like Media Toggle and the voice suite), Switch, Checkbox, Radio, Slider, and OTP Field all fire through the ambient provider. Without one, every trigger is a silent no-op, so components work unchanged.

<HapticsProvider sound={false}>  // buzz only, no click audio
<HapticsProvider enabled={false}> // everything off (e.g. a user setting)

Per-component control

Button and Toggle take a haptic prop — true (default) fires "tap" on press, a preset name overrides it, false opts out:

<Button haptic="success">Save</Button>
<Button haptic={false}>Quiet</Button>

The presets: tap (press), tick (a state committing — toggle, check, slider release, OTP digit), success, and error (OTP fires it when invalid flips on). Custom components reach the channel with useHaptics():

const { trigger } = useHaptics()
trigger("tick") // safe anywhere — no-op without a provider

Platform support

Powered by web-haptics: the Vibration API on Android, its taptic <input switch> trick on iOS Safari, and click audio everywhere when sound is on. Where nothing is available it degrades silently — feedback never blocks the interaction or throws. Haptics are orthogonal to prefers-reduced-motion; expose the provider's enabled prop as a user setting if you want an off switch.