v156 · web haptics · canonical + migration
Semantic vs vibrate
The smallest real use of the new surface — navigator.playHaptics("tick") — side by side with the API it is designed to replace. Both buttons execute the actual call and report the actual outcome. Nothing here simulates success: the proposed API returns undefined with no success signal by design, and the legacy API's boolean return value is shown exactly as the browser produced it.
Two calls, two philosophies
navigator.playHaptics()
// intent, not milliseconds
navigator.playHaptics("tick", 0.8);
// → undefined, always.
// No success signal: content cannot
// tell whether hardware played.
navigator.vibrate()
// raw pattern: vibrate 50ms,
// pause 100ms, vibrate 50ms
const ok = navigator.vibrate([50, 100, 50]);
// → boolean. true = request accepted;
// it still plays nothing without
// vibration hardware.
| contract | playHaptics (proposed) | vibrate (shipped) |
|---|---|---|
| you express | intent: hint / edge / tick / align | milliseconds: [50, 100, 50] |
| return value | undefined — no success signal (anti-fingerprinting) | boolean — request accepted or rejected |
| target hardware | most recent input device (haptic touchpad, mouse, pen); never rerouted | device vibration motor (phones); desktop silently no-ops |
| activation gate | sticky user activation required; silently ignored without it | without sticky activation the call returns false |
| policy gate | "haptics" permissions policy, default self | none (predates permissions policy) |
| intensity | 0.0–1.0, multiplied with the system setting | none — only durations |