# Haptics

> Haptic feedback for the web in one call: short vibration ticks on Android and the system tick on iPhone, silent everywhere else.

- Type: React helper (Hooks & Utilities)
- Access: Pro (the source needs a Wingo UI Pro plan, see https://wingo-ui.com/pricing)
- Version: 1.0.0
- Install: `npx wingo-ui@latest add haptics`
- Docs: https://wingo-ui.com/components/haptics

## Interaction

Tap a tile on a phone to feel each kind: a faint selection detent, light, medium and heavy impacts, and the success, warning and error patterns drawn as bars on the tile. Send plays the kind picked in the playground. On a desktop nothing vibrates and the readout says haptic() returned false; turn enabled off to see every call return false on a phone too.

## Installation

```bash
npx wingo-ui@latest add haptics
```

Pro item: run `npx wingo-ui@latest login` once with a Pro account. The CLI adds the files, their dependencies and a version record for updates.

With shadcn: `npx shadcn@latest add @wingo-ui/haptics` (needs the @wingo-ui registry with your API key in components.json)

Files:

- `lib/haptics.ts`

## Usage

```tsx
"use client"

import { haptic } from "@/lib/haptics"
import { Button } from "@/components/ui/button"

export function PayButton({ onPay }: { onPay: () => Promise<void> }) {
  return (
    <Button
      onClick={async () => {
        haptic("light")
        try {
          await onPay()
          haptic("success")
        } catch {
          haptic("error")
        }
      }}
    >
      Pay $1,850
    </Button>
  )
}
```

## API

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `kind?` | `"selection" \| "light" \| "medium" \| "heavy" \| "success" \| "warning" \| "error"` | `"light"` | haptic(kind?, options?): the feel. selection for wheel and slider detents, light for taps and toggles, medium for a snap or a crossed threshold, heavy for a committed full swipe or a drop, success / warning / error for outcomes. Returns true when a haptic was sent. |
| `enabled?` | `boolean` | `true` | configureHaptics({ enabled }): the app-wide switch, e.g. a Vibrations setting. Off, haptic() does nothing unless called with { force: true }. |
| `iosFallback?` | `boolean` | `true` | configureHaptics({ iosFallback }): Safari on iOS has no vibrate, but toggling a native switch input plays the system tick (iOS 17.4+). The lib keeps one hidden, aria-hidden switch at the end of <body> and clicks it; the click never bubbles into the page. |
| `force?` | `boolean` |  | haptic(kind, { force: true }) plays even when haptics are turned off app-wide (a test button next to the setting). |
| `HAPTIC_PATTERNS?` | `Record<HapticKind, number \| number[]>` |  | The vibration patterns in ms: selection 4, light 8, medium 14, heavy 22, success [10, 60, 16], warning [16, 70, 16], error [22, 50, 22, 50, 22]. iOS repeats its one tick 1, 2 or 3 times instead. |
| `supportsHaptics?` | `() => boolean` |  | True when this device can play a haptic (vibrate, or an iPhone / iPad with the fallback on). False on the server: call it in an effect or a handler. |
| `getHapticsConfig?` | `() => HapticsConfig` |  | The current { enabled, iosFallback }. |

## Examples

- **Quantity stepper**: Each step plays a light selection tick; pressing past 1 or 6 plays the warning pattern instead.

## See also

- [useLongPress](https://wingo-ui.com/components/use-long-press) ([Markdown](https://wingo-ui.com/components/use-long-press.md))
- [Motion presets](https://wingo-ui.com/components/motion) ([Markdown](https://wingo-ui.com/components/motion.md))
- [Button](https://wingo-ui.com/components/button) ([Markdown](https://wingo-ui.com/components/button.md))

---

Canonical: https://wingo-ui.com/components/haptics
More components: https://wingo-ui.com/components · Index for agents: https://wingo-ui.com/llms.txt
