Launch Week Day 1: Socket for Jira Is Now Available.Learn More
Socket
Book a DemoSign in
Socket

react-native-haptic-feedback

Package Overview
Dependencies
Maintainers
1
Versions
44
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

react-native-haptic-feedback

Basic haptic feedback for iOS and android

latest
Source
npmnpm
Version
3.0.0
Version published
Weekly downloads
296K
-6.59%
Maintainers
1
Weekly downloads
 
Created
Source

react-native-haptic-feedback

The most complete haptic feedback library for React Native — Core Haptics on iOS, rich Composition API on Android, custom patterns, and a developer-friendly hook.

GitHub Sponsors npm npm downloads

If this library saves you time, consider sponsoring its development. ⭐

Contributions Welcome

Contributors

Made with contrib.rocks.

Requirements

PlatformMinimum version
iOS13.0 (Core Haptics)
AndroidAPI 23 (Android 6.0)
React Native0.71.0
WebBrowsers with Vibration API

Installation

Stable (v2):

npm install react-native-haptic-feedback
# or
yarn add react-native-haptic-feedback

Pre-release (v3 — battle testing):

npm install react-native-haptic-feedback@next
# or
yarn add react-native-haptic-feedback@next

React Native 0.71+ uses auto-linking — no extra steps needed.

Basic Usage

import RNHapticFeedback from "react-native-haptic-feedback";

RNHapticFeedback.trigger("impactMedium");

// With options
RNHapticFeedback.trigger("notificationSuccess", {
  enableVibrateFallback: true, // iOS: vibrate if Core Haptics unavailable
  ignoreAndroidSystemSettings: false,
});

Named exports are also available:

import { trigger } from "react-native-haptic-feedback";
trigger("impactLight");

API Reference

trigger(type, options?)

Play a predefined haptic type.

RNHapticFeedback.trigger(type: HapticFeedbackTypes | string, options?: HapticOptions): void
OptionDefaultDescription
enableVibrateFallbackfalseiOS: play AudioServicesPlaySystemSound as a last resort on devices with no Taptic Engine (e.g. iPod touch). Has no effect on devices that have a Taptic Engine — those use UIKit generators automatically.
ignoreAndroidSystemSettingsfalseAndroid: trigger even if vibration is disabled in system settings

impact(type?, intensity?, options?)

Play a haptic with a custom intensity (0.0–1.0). On iOS the intensity is applied precisely via CHHapticEngine; on Android it maps to VibrationEffect amplitude.

RNHapticFeedback.impact(
  type?: HapticFeedbackTypes,   // default: 'impactMedium'
  intensity?: number,            // 0.0–1.0, default: 0.7
  options?: HapticOptions
): void
import { impact } from "react-native-haptic-feedback";

impact("impactHeavy", 0.3); // gentle heavy tap
impact("rigid", 1.0); // full-force crisp tap

stop()

Cancel the current haptic player and stop the engine.

RNHapticFeedback.stop(): void

isSupported()

Synchronously returns true if Core Haptics is supported on the device (iOS 13+ hardware). Always returns true on Android if the device has a vibrator.

RNHapticFeedback.isSupported(): boolean

triggerPattern(events, options?)

Play a custom sequence of haptic events.

RNHapticFeedback.triggerPattern(events: HapticEvent[], options?: HapticOptions): void
interface HapticEvent {
  time: number; // ms from pattern start
  type?: "transient" | "continuous";
  duration?: number; // ms — for continuous events only
  intensity?: number; // 0.0–1.0
  sharpness?: number; // 0.0–1.0
}

playAHAP(fileName)

Play an Apple Haptic and Audio Pattern (.ahap) file. iOS only — resolves immediately on Android.

RNHapticFeedback.playAHAP(fileName: string): Promise<void>

Pass the file name (e.g. "heartbeat.ahap") without any path prefix. The native code searches for the file in two locations, in order:

  • A haptics/ subdirectory inside the app bundle
  • The bundle root

For cross-platform usage, prefer playHaptic below.

Setting up AHAP files in Xcode

AHAP files must be added to the iOS app bundle — they are not bundled by Metro or CocoaPods. Follow these steps:

  • Create a haptics/ folder inside your Xcode project directory (e.g. ios/YourApp/haptics/).

  • Place your .ahap files in that folder:

ios/YourApp/haptics/
├── heartbeat.ahap
├── rumble.ahap
└── celebration.ahap
  • Add the files to Xcode:

    • Open your .xcworkspace in Xcode
    • Right-click your app target in the project navigator → Add Files to "YourApp"
    • Select the .ahap files (or the entire haptics/ folder)
    • Make sure "Copy items if needed" is unchecked (files are already in the project directory)
    • Make sure your app target is checked under "Add to targets"
  • Verify they appear in Build Phases:

    • Select your app target → Build PhasesCopy Bundle Resources
    • All .ahap files should be listed there. If not, click + and add them.

Once added, the files are bundled into the app at build time and playAHAP("heartbeat.ahap") will find them.

AHAP file format

An .ahap file is a JSON document describing haptic events. Here's a minimal example:

{
  "Version": 1.0,
  "Pattern": [
    {
      "Event": {
        "EventType": "HapticTransient",
        "Time": 0.0,
        "EventParameters": [
          { "ParameterID": "HapticIntensity", "ParameterValue": 0.5 },
          { "ParameterID": "HapticSharpness", "ParameterValue": 0.3 }
        ]
      }
    },
    {
      "Event": {
        "EventType": "HapticTransient",
        "Time": 0.15,
        "EventParameters": [
          { "ParameterID": "HapticIntensity", "ParameterValue": 1.0 },
          { "ParameterID": "HapticSharpness", "ParameterValue": 0.5 }
        ]
      }
    }
  ]
}

See Apple's Representing Haptic Patterns in AHAP Files for the full specification. You can also design patterns visually using the Haptic Sampler section in Xcode's Core Haptics tools.

playHaptic(ahapFile, fallback, options?)

Cross-platform wrapper for AHAP playback. Plays the .ahap file on iOS and falls back to a triggerPattern call on Android.

import { playHaptic, pattern } from "react-native-haptic-feedback";

// iOS: plays my-effect.ahap via Core Haptics
// Android: plays the fallback pattern via Vibrator API
await playHaptic("my-effect.ahap", pattern("oO.O"));

This is the recommended approach for cross-platform apps — design your haptic in an .ahap file for the best iOS experience, and provide a pattern() fallback for Android.

getSystemHapticStatus()

Returns the device's haptic availability and — on Android — current ringer mode.

RNHapticFeedback.getSystemHapticStatus(): Promise<SystemHapticStatus>

interface SystemHapticStatus {
  vibrationEnabled: boolean;
  /** Android: 'silent' | 'vibrate' | 'normal'. iOS: null (not exposed by the OS). */
  ringerMode: 'silent' | 'vibrate' | 'normal' | null;
}

Use the isRingerSilent helper to check for silent mode:

import {
  getSystemHapticStatus,
  isRingerSilent,
} from "react-native-haptic-feedback";

const status = await getSystemHapticStatus();
if (isRingerSilent(status)) {
  // Android: ringer is silent — show a visual indicator instead
}
// iOS: ringerMode is always null (not exposed by the OS), so isRingerSilent returns false

setEnabled(value) / isEnabled()

Library-wide kill switch. When disabled, all trigger, triggerPattern, playAHAP, playHaptic, and stop calls become no-ops.

import RNHapticFeedback from "react-native-haptic-feedback";

// Respect user's in-app haptics preference
RNHapticFeedback.setEnabled(userPreference.hapticsEnabled);

// Check current state
if (RNHapticFeedback.isEnabled()) {
  /* ... */
}

The setting is in-memory only — persist it yourself (e.g. AsyncStorage) if it should survive app restarts.

Pattern Notation Helper

Build HapticEvent[] from a compact string notation:

CharacterMeaningTime advanceTotal O_O spacing
oSoft transient (intensity 0.4, sharpness 0.4)100 ms
OStrong transient (intensity 1.0, sharpness 0.8)100 ms
.Short gap+150 ms250 ms
-Medium gap+400 ms500 ms
=Long gap+1000 ms1100 ms

Consecutive haptic events (OO) are spaced 100 ms apart — the minimum interval the Taptic Engine (iOS) and vibrator motors (Android) can render as distinct pulses. Gap characters add progressively more space on top: . for a short beat (250 ms), - for a half-second pause, = for a full second rest.

import { pattern, PATTERN_CHARS } from "react-native-haptic-feedback";
import type { PatternChar } from "react-native-haptic-feedback";

RNHapticFeedback.triggerPattern(pattern("oO.O"));
// → soft, strong, 100ms pause, strong

pattern() throws a TypeError at runtime if the string contains any character not in PATTERN_CHARS.

Compile-time validation: When you pass a string literal, TypeScript catches invalid characters before runtime:

import type { AssertValidPattern } from "react-native-haptic-feedback";

pattern("oO.O"); // ✅ compiles
pattern("oXO"); // ✗ TypeScript error — 'X' is not a valid PatternChar

This works automatically — no extra setup needed. If the argument is a runtime string variable (not a literal), validation happens at runtime via TypeError instead.

Programmatic validation — use PATTERN_CHARS to check user input before calling pattern():

import { PATTERN_CHARS } from "react-native-haptic-feedback";
import type { PatternChar } from "react-native-haptic-feedback";

const valid = [...input].every((c) => PATTERN_CHARS.has(c as PatternChar));

Built-in Presets

import { Patterns } from "react-native-haptic-feedback";

RNHapticFeedback.triggerPattern(Patterns.success);
RNHapticFeedback.triggerPattern(Patterns.error);
RNHapticFeedback.triggerPattern(Patterns.warning);
RNHapticFeedback.triggerPattern(Patterns.heartbeat);
RNHapticFeedback.triggerPattern(Patterns.tripleClick);
RNHapticFeedback.triggerPattern(Patterns.notification);

useHaptics Hook

import { useHaptics } from "react-native-haptic-feedback";

function MyButton() {
  const haptics = useHaptics({ enableVibrateFallback: true });

  return (
    <Pressable onPress={() => haptics.trigger('impactMedium')}>
      Press me
    </Pressable>
  );
}

The hook accepts default options that are merged with per-call overrides.

TouchableHaptic Component

A drop-in Pressable wrapper that automatically triggers haptic feedback. Accepts all standard PressableProps plus three extra props:

PropTypeDefaultDescription
hapticTypeHapticFeedbackTypesimpactMediumFeedback type to play
hapticTrigger'onPressIn' | 'onPress' | 'onLongPress'onPressInWhich event triggers haptics
hapticOptionsHapticOptionsOptions forwarded to trigger()
import { TouchableHaptic } from "react-native-haptic-feedback";

<TouchableHaptic
  hapticType="impactMedium"
  hapticTrigger="onPressIn"
  onPress={handlePress}
  style={styles.button}
>
  <Text>Press me</Text>
</TouchableHaptic>

Available Feedback Types

TypeAndroidiOSNotes
impactLightAPI 31+: PRIMITIVE_TICK
impactMediumAPI 31+: PRIMITIVE_CLICK
impactHeavyAPI 31+: PRIMITIVE_HEAVY_CLICK
rigidAPI 31+: PRIMITIVE_CLICK (scale 0.9)
softAPI 31+: PRIMITIVE_TICK (scale 0.3)
notificationSuccess
notificationWarning
notificationError
selection
confirmAndroid API 30+: CONFIRM; fallback waveform on older
rejectAndroid API 30+: REJECT; fallback waveform on older
gestureStartAndroid API 30+: GESTURE_START; fallback waveform on older
gestureEndAndroid API 30+: GESTURE_END; fallback waveform on older
segmentTickAndroid API 30+: SEGMENT_TICK; fallback waveform on older
segmentFrequentTickAndroid API 30+: SEGMENT_FREQUENT_TICK; fallback waveform on older
toggleOnAndroid API 34+: TOGGLE_ON; fallback waveform on older
toggleOffAndroid API 34+: TOGGLE_OFF; fallback waveform on older
dragStartAndroid API 34+: DRAG_START; fallback waveform on older
gestureThresholdActivateAndroid API 34+: GESTURE_THRESHOLD_ACTIVATE; fallback on older
gestureThresholdDeactivateAndroid API 34+: GESTURE_THRESHOLD_DEACTIVATE; fallback on older
noHapticsAndroid API 34+: NO_HAPTICS (explicit no-op)
clockTickiOS: Core Haptics approximation
contextClickiOS: Core Haptics approximation
keyboardPressiOS: Core Haptics approximation
keyboardReleaseiOS: Core Haptics approximation
keyboardTapiOS: Core Haptics approximation
longPressiOS: Core Haptics approximation
textHandleMoveiOS: Core Haptics approximation
virtualKeyiOS: Core Haptics approximation
virtualKeyReleaseiOS: Core Haptics approximation
effectClickAndroid API 29+; iOS: Core Haptics approximation
effectDoubleClickAndroid API 29+; iOS: Core Haptics approximation
effectHeavyClickAndroid API 29+; iOS: Core Haptics approximation
effectTickAndroid API 29+; iOS: Core Haptics approximation

Platform internals

Understanding how each haptic type is rendered helps when diagnosing unexpected behaviour on specific devices.

iOS — three-tier fallback chain

Every trigger() call on iOS walks this chain and stops at the first tier that succeeds:

TierHardware requirementWhat fires
1 — Core HapticsiPhone 8+ / iPad Pro (iOS 13+)CHHapticEngine — full per-type patterns with custom intensity & sharpness
2 — UIKit generatorsTaptic Engine (iPhone 6s, 7, SE 1st gen on iOS 13+)UIImpactFeedbackGenerator / UINotificationFeedbackGenerator / UISelectionFeedbackGenerator — per-type, semantically mapped
3 — Audio vibrationAny deviceAudioServicesPlaySystemSound(kSystemSoundID_Vibrate)only fires if enableVibrateFallback: true

Tier 3 exists for devices with no Taptic Engine at all (e.g. iPod touch 7th gen). On any device with a Taptic Engine, Tier 2 handles it and Tier 3 is unnecessary.

UIKit semantic mapping (Tier 2):

UIKit generatorTypes
UINotificationFeedbackGenerator(.success)notificationSuccess
UINotificationFeedbackGenerator(.warning)notificationWarning
UINotificationFeedbackGenerator(.error)notificationError, reject
UIImpactFeedbackGenerator(.light)impactLight, soft, effectTick, clockTick, gestureStart, segmentTick, segmentFrequentTick, textHandleMove
UIImpactFeedbackGenerator(.medium)impactMedium, confirm, toggleOn, toggleOff, effectClick, effectDoubleClick and all other types
UIImpactFeedbackGenerator(.heavy)impactHeavy, rigid, effectHeavyClick, longPress
UISelectionFeedbackGeneratorselection, keyboardPress, keyboardRelease, keyboardTap, virtualKey, virtualKeyRelease, gestureEnd, contextClick

Android — two-tier fallback chain

TierAPI levelWhat fires
1 — performHapticFeedbackAll (via HapticFeedbackConstants)System-quality haptic constant via the activity's decorView — respects user system settings unless ignoreAndroidSystemSettings: true
2 — Vibrator APIAPI 23+VibrationEffect.createWaveform (API 26+) or raw waveform; API 31+ uses VibrationEffect.Composition primitives for richer quality

Tier 1 is skipped when ignoreAndroidSystemSettings: true (because performHapticFeedback cannot override system settings), falling directly to Tier 2.

Android API-level progression:

APIImprovement
23Raw waveform vibration (minimum supported)
26VibrationEffect.createWaveform with per-step amplitudes
29VibrationEffect.createPredefined for effect* types
30HapticFeedbackConstants for confirm, reject, gesture*, segment*
31VibrationEffect.Composition primitives (richer impact feel)
33VibrationAttributes.USAGE_TOUCH — vibrations respect system haptic-preference settings
34HapticFeedbackConstants for toggleOn, toggleOff, dragStart, gestureThreshold*, noHaptics

Jest Mock

// In your test file:
jest.mock("react-native-haptic-feedback");

// All methods are automatically mocked:
// trigger, stop, isSupported (→ true), triggerPattern, playAHAP (→ Promise.resolve()),
// getSystemHapticStatus (→ { vibrationEnabled: true, ringerMode: 'normal' } on Android, ringerMode: null on iOS),
// useHaptics, pattern, Patterns

Migrating from v2 to v3

Breaking changes

  • iOS minimum target is now 13.0 — remove any <13.0 deployment-target overrides.
  • React Native minimum is 0.71 — update your peer dependency if needed.
  • The internal DeviceUtils class is removed — if you referenced it directly, remove those imports.
  • enableVibrateFallback on devices without Core Haptics now calls kSystemSoundID_Vibrate instead of the UIKit generator path.

Upgrade steps

# Pre-release (recommended for testing)
npm install react-native-haptic-feedback@next
cd ios && pod install

All existing trigger() call-sites continue to work without changes. The new confirm, reject, gestureStart/End, segmentTick/FrequentTick, toggleOn/Off types are additive.

Acknowledgements

  • expo-ahap by @EvanBacon — the AhapType TypeScript definitions exported by this library are modelled after the types in expo-ahap.
  • All contributors who submitted issues and pull requests.

Troubleshooting

Haptics not firing on iOS simulator — Core Haptics does not work in the iOS Simulator. Test on a physical device.

isSupported() returns false — the device does not have a Taptic Engine (iPhone 7 or older without the A9 chip, or iPads). Use enableVibrateFallback: true to fall back to system vibration.

Android vibration seems weak — upgrade your target device to API 31+ and ensure the device has a high-quality actuator. Use triggerPattern with explicit amplitudes for more control.

Keywords

react-native

FAQs

Package last updated on 29 Mar 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts