iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Haptics

Capacitor’s Haptics plugin produces vibration patterns and tactile feedback on iOS and Android. Use light, medium, or heavy impacts for actions; selection for picker changes; notification for success/warning/error. Subtle haptics dramatically improve perceived quality.

Plugin, impact, selection, notification

EXAMPLE
// 1) Install
// npm install @capacitor/haptics
// npx cap sync

import { Haptics, ImpactStyle, NotificationType } from '@capacitor/haptics';

// 2) Impact — for taps, button presses
await Haptics.impact({ style: ImpactStyle.Light });
await Haptics.impact({ style: ImpactStyle.Medium });
await Haptics.impact({ style: ImpactStyle.Heavy });

// 3) Selection — for picker / slider changes
await Haptics.selectionStart();
// User drags slider...
await Haptics.selectionChanged();    // call on each step
await Haptics.selectionEnd();

// 4) Notification — for success / warning / error
await Haptics.notification({ type: NotificationType.Success });
await Haptics.notification({ type: NotificationType.Warning });
await Haptics.notification({ type: NotificationType.Error });

// 5) Generic vibrate
await Haptics.vibrate();                       // default ~200ms
await Haptics.vibrate({ duration: 100 });      // ms

// 6) Real-world examples

// Button tap
<ion-button (click)="buy()">Buy</ion-button>
async buy() {
    await Haptics.impact({ style: ImpactStyle.Light });
    // ... actual logic
}

// Successful save
async save() {
    try {
        await api.save(this.form);
        await Haptics.notification({ type: NotificationType.Success });
        this.showToast('Saved!');
    } catch {
        await Haptics.notification({ type: NotificationType.Error });
        this.showToast('Failed', 'error');
    }
}

// Pull-to-refresh end
<ion-refresher (ionRefresh)="refresh($event)">
    <ion-refresher-content></ion-refresher-content>
</ion-refresher>
async refresh(event) {
    await this.loadData();
    await Haptics.impact({ style: ImpactStyle.Medium });
    event.target.complete();
}

// Slider step
<ion-range (ionChange)="onChange($event)" min="0" max="10"></ion-range>

prevValue = 0;
async onChange(e) {
    const v = e.detail.value;
    if (v !== this.prevValue) {
        await Haptics.selectionChanged();
        this.prevValue = v;
    }
}

// 7) Web fallback
// On the web, Haptics uses the Vibration API (when available):
//   navigator.vibrate(...)
// • Chrome on Android — works
// • iOS Safari — does NOT support; no-op
// • Desktop — no-op

// 8) Reactive: only when the user opts in
class HapticsService {
    enabled = true;

    async impact(style: ImpactStyle = ImpactStyle.Light) {
        if (!this.enabled) return;
        await Haptics.impact({ style });
    }
}

// Provide a settings toggle: 'Haptic feedback' on/off, default on.

// 9) Patterns — when to use each
// Light impact:    button tap, list selection, gentle confirmation
// Medium impact:   toggle change, swipe complete, modal open
// Heavy impact:    drag-and-drop snap, achievement unlock
// Selection:       picker, slider, segmented control
// Notification:    success / warning / error states
// Custom vibrate:  rarely; prefer specific feedback above

// 10) Accessibility considerations
// • Haptics SUPPLEMENT visual feedback; don't replace it
// • Provide a global on/off setting
// • Don't rely on haptics alone for critical info
// • iOS: Reduce Motion users may want haptics off too

// 11) Game-style continuous feedback
// For sustained vibration (e.g. game alerts), trigger multiple times:
async function alarmSequence() {
    for (let i = 0; i < 3; i++) {
        await Haptics.notification({ type: NotificationType.Warning });
        await new Promise((r) => setTimeout(r, 300));
    }
}

// 12) Performance + battery
// • Each haptic costs power
// • Excessive haptics annoy users (e.g. on every keystroke)
// • Don't fire during animations every frame; throttle

// 13) iOS specifics
// • iOS Taptic Engine: precise, low-latency
// • Requires actual device (simulator doesn't vibrate)
// • Older iPhones (pre-7) have weaker engine

// 14) Android specifics
// • Vibration API varies by device — newer ones support more nuance
// • Some manufacturers (OPPO, Xiaomi) restrict background vibrations
// • Test on a range of devices

// 15) Common bugs
// • Calling Haptics on web without checking → no-op + console error in some cases
// • Over-haptic-ing → users disable in settings
// • Forgetting to await — order matters; await for predictable UX
// • Triggering haptics during system gestures → conflicts with platform haptics
// • Not testing on real device — simulator never vibrates
// • Mixing platform-specific vibration patterns — stick with Capacitor's API
// • Using selectionChanged without selectionStart/End → may misbehave on some devices
// • Haptic on EVERY animation frame → battery drain + annoyance
// • No setting for users to disable — accessibility issue
// • Ignoring iOS 'Reduce Motion' preference

Why it matters

Capacitor Haptics adds the Taptic Engine on iOS and vibration patterns on Android with one API. Use impact (light/medium/heavy) for taps, selection for slider/picker changes, notification for success/warning/error. Pair with visual feedback (haptics supplement, never replace), provide a user toggle for accessibility, and never spam haptics during animations.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
import { Haptics, ImpactStyle } from '@capacitor/haptics';
await Haptics.impact({ style: ImpactStyle.Medium });
Try it Yourself »

Discussion

Loading…