webdevpuneet.com

Vibration API Pattern Demo — Free navigator.vibrate() UI

Vibration API Pattern Demo · Buttons · Plain HTML, CSS & JS · Live preview

CategoryButtons

Copy & paste

Source Code

<section class="vpd-wrap">
  <span class="vpd-tag">navigator.vibrate</span>
  <h1>Vibration patterns</h1>
  <p id="vpdStatus">Tap a button to fire a real navigator.vibrate() pattern on supporting devices.</p>

  <div class="vpd-pulse-stage">
    <div class="vpd-pulse" id="vpdPulse"></div>
  </div>

  <div class="vpd-grid">
    <button class="vpd-btn" id="vpdShort" data-pattern="120">
      <span class="vpd-btn-title">Short pulse</span>
      <span class="vpd-btn-sub">120ms · single buzz</span>
    </button>
    <button class="vpd-btn" id="vpdDouble" data-pattern="80,90,80">
      <span class="vpd-btn-title">Double tap</span>
      <span class="vpd-btn-sub">80·90·80ms pattern</span>
    </button>
    <button class="vpd-btn" id="vpdLong" data-pattern="450">
      <span class="vpd-btn-title">Long buzz</span>
      <span class="vpd-btn-sub">450ms · sustained</span>
    </button>
    <button class="vpd-btn" id="vpdSos" data-pattern="90,60,90,60,90,180,220,60,220,60,220,180,90,60,90,60,90">
      <span class="vpd-btn-title">SOS pattern</span>
      <span class="vpd-btn-sub">morse-style burst</span>
    </button>
  </div>

  <button class="vpd-stop" id="vpdStop">Cancel vibration</button>
  <p class="vpd-note" id="vpdNote">Checking for Vibration API support…</p>
</section>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month, 7 days free), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

Real navigator.vibrate calls
Genuine pattern arrays, not a simulated stand-in.
Array and number patterns
Covers both accepted forms of the Vibration API.
Synced visual pulse
Animation timing mirrors the exact vibration pattern.
Return-value awareness
Distinguishes unsupported from silently-declined.
Cancel button
navigator.vibrate(0) stops an in-progress pattern.
SOS pattern preset
A morse-style burst showing multi-segment timing.
Desktop-honest copy
Explains why desktop won't feel the vibration.
No dependencies
Pure vanilla JS against the native API.

About this UI Snippet

Vibration API Pattern Demo — Real Haptic Patterns With a Visible Twin

Screenshot of the Vibration API Pattern Demo snippet rendered live

This snippet fires genuine navigator.vibrate() calls with distinct timing patterns, then mirrors each one as an on-screen pulse animation so the demo communicates what happened even when you can't feel it — which, on a desktop browser previewing this snippet, is every time.

Patterns as arrays, not just numbers

navigator.vibrate() accepts either a single millisecond number for one buzz, or an array like [80, 90, 80] meaning vibrate 80ms, pause 90ms, vibrate 80ms. This snippet uses both forms: a plain number for the short pulse and long buzz, and arrays for the double-tap and SOS patterns, parsed from a data-pattern attribute on each button.

The on-screen pulse is timed off the same array

animatePulse() walks the same pattern array the vibration call receives, scheduling a CSS animation restart at every "vibrate" segment (the even-indexed entries) using setTimeout offsets that sum the preceding durations. Because both the haptic call and the visual pulse read from one source of truth, the pulse never drifts out of sync with what the hardware is (or would be) doing.

Honest about what happens on desktop

Vibration hardware is a phone/tablet feature. On desktop Chrome, Firefox, and friends, navigator.vibrate frequently exists as a function and returns true, but produces zero physical sensation since there's no vibration motor to drive — the call isn't fake, it's just inert on that hardware. The status line and note explicitly call this out rather than implying the button "worked" in a way the user can feel.

Feature detection plus a false return

Beyond checking typeof navigator.vibrate === 'function', the demo also branches on the call's own return value: navigator.vibrate() returns false without throwing when the document isn't in an "active"/focused state, when a Permissions-Policy blocks it in a sandboxed iframe, or when the OS has vibration switched off. Both paths — unsupported entirely, and supported-but-declined — get distinct, honest status copy instead of a generic error.

Cancel support

Calling navigator.vibrate(0) (or an empty array) cancels any in-progress pattern immediately; the Cancel button wires this up alongside resetting the on-screen pulse, useful for patterns like the SOS burst that otherwise run for a couple of seconds.

Pair this with a notification permission prompt for a fuller "device capability" showcase, or a badging API demo for another rarely-covered browser capability.

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSFour pattern buttons and a pulse indicator render.
  2. 2
    Click a pattern buttonnavigator.vibrate() fires with that pattern's timing.
  3. 3
    Watch the pulseAn on-screen pulse animates in sync, visible even on desktop.
  4. 4
    Try it on a phoneSupporting Android browsers produce a real physical buzz.
  5. 5
    Cancel mid-patternClick Cancel to stop a long or SOS pattern early.
  6. 6
    Read the status lineIt reports supported, declined, or unsupported explicitly.

Real-world uses

Common Use Cases

Mobile web game feedback
Give haptic feedback on hits, combos or game over, using genuine navigator.vibrate() pattern arrays instead of a simulated stand-in.
Form validation cues
Add a short buzz on an invalid submit alongside the visible error, with the return value telling you whether vibration is unsupported or silently declined.
Notification alerts
Pair with a notification permission prompt so a distinct vibration pattern accompanies each different kind of alert.
Accessibility cues
Offer non-visual feedback for low-vision mobile users, with a synced on-screen pulse so the demo stays meaningful on desktop.
Timers and capability showcases
Signal that a countdown has finished with a distinct pattern, or show alongside a badging API demo in a browser features showcase.

Got questions?

Frequently Asked Questions

No. As of this writing, iOS Safari (and all browsers on iOS, since they share WebKit) does not implement navigator.vibrate at all — Apple has never shipped it. This snippet detects that absence via typeof navigator.vibrate === 'function' and falls back to the on-screen pulse animation only, with status copy explaining the platform gap rather than pretending it worked.

Vibration requires physical hardware — a vibration motor — which desktop and laptop computers don't have. On many desktop browsers navigator.vibrate is still present as a function and can return true, but there's nothing to actuate. The synced on-screen pulse exists specifically so the demo communicates timing and pattern shape even where hardware feedback is impossible.

The Vibration API is designed to fail silently rather than throw. It returns false (instead of throwing) when the calling document isn't in an active/focused state, when a Permissions-Policy denies the vibrate feature to the current frame (common in sandboxed preview iframes), or when the OS has vibration disabled system-wide. This snippet checks the return value and shows distinct status copy for that case versus total unsupported.

A single number vibrates once for that many milliseconds. An array alternates vibrate/pause/vibrate/pause starting with vibrate — so [80, 90, 80] means vibrate 80ms, pause 90ms, vibrate 80ms. This snippet's SOS button uses a longer array to demonstrate a multi-segment morse-style pattern, and the on-screen pulse reads the same array to time its own animation.

Wrap the pattern-firing logic in a handler that checks typeof navigator.vibrate === 'function' before calling it, and keep the pulse animation as CSS classes toggled by state rather than direct DOM manipulation. Cancel any in-progress vibration (navigator.vibrate(0)) in a cleanup/unmount effect if your component might unmount mid-pattern.