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…