react-native-haptic-timeline
v1.0.1
Published
Meaningful haptic feedback sequences for React Native (Expo & CLI)
Maintainers
Readme
react-native-haptic-timeline 📳
Meaningful, scheduled, and customizable haptic feedback sequences for React Native and Expo. Orchestrate haptic steps sequentially along a timeline with zero native dependencies, built-in race condition protection, loop/repeat settings, custom step durations, and hook lifecycle cleanups.
✨ Key Features
- 📱 CLI & Expo Out-of-the-Box: Works seamlessly across both bare React Native CLI and managed Expo workflows.
- 🔒 Race Condition Protection: Never deal with overlapping, messy vibrations again! Triggering a new timeline automatically and safely interrupts any active pattern.
- ⏹️ Immediate Stop Controller: Halt running timelines and physical vibrations instantly using the global
stop()API. - 🔁 Loop & Repeat Controls: Easily configure patterns to loop infinitely or repeat a fixed number of times (perfect for rings, alarms, or progress loops).
- ⏱️ Vibration Duration Override: Set custom vibration lengths (in milliseconds) directly on individual steps.
- 🧹 Auto-Cleanup Hook: The
useHapticPatternshook automatically cancels pending vibration timers if the hosting component unmounts. - ⚡ Zero-Config Fallback: Automatically falls back to React Native's standard
VibrationAPI if no custom native driver is set.
📦 Installation
Install the package via your preferred manager:
# Using npm
npm install react-native-haptic-timeline
# Using yarn
yarn add react-native-haptic-timeline
# Using expo
npx expo install react-native-haptic-timeline🚀 Setup & Custom Drivers
By default, the package falls back to React Native's standard Vibration API. Because standard vibration cannot fully simulate distinct tactile feedback weights (like light selection ticks vs warning notification vibrations) on iOS/Android, it is highly recommended to configure a custom driver.
1. For Expo (expo-haptics)
In your root layout (e.g. app/_layout.tsx), initialize expo-haptics:
import * as Haptics from 'expo-haptics';
import { setHapticDriver, HapticType } from 'react-native-haptic-timeline';
setHapticDriver({
trigger: (type: HapticType, duration?: number) => {
switch (type) {
case 'light': Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light); break;
case 'medium': Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium); break;
case 'heavy': Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Heavy); break;
case 'success': Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success); break;
case 'warning': Haptics.notificationAsync(Haptics.NotificationFeedbackType.Warning); break;
case 'error': Haptics.notificationAsync(Haptics.NotificationFeedbackType.Error); break;
default: Haptics.selectionAsync();
}
}
});2. For React Native CLI (react-native-haptic-feedback)
In your entry file (e.g., index.js), initialize react-native-haptic-feedback:
import ReactNativeHapticFeedback from 'react-native-haptic-feedback';
import { setHapticDriver, HapticType } from 'react-native-haptic-timeline';
setHapticDriver({
trigger: (type: HapticType, duration?: number) => {
const options = {
enableVibrateFallback: true,
ignoreAndroidSystemSettings: false,
};
ReactNativeHapticFeedback.trigger(type, options);
}
});🛠️ Usage
Basic Trigger
import { trigger } from 'react-native-haptic-timeline';
// Trigger a pre-defined preset pattern
const onLikePress = () => {
trigger('heartbeat');
};
const onErrorOccurred = () => {
trigger('error-triple');
};Playback Options (Loop & Repeat)
Pass custom options to trigger repeating timelines:
import { trigger } from 'react-native-haptic-timeline';
// Repeat the heartbeat timeline 3 times
trigger('heartbeat', { repeat: 3 });
// Loop the warning timeline infinitely (until stop() is called)
trigger('warning-pulse', { loop: true });Stop/Cancel Active Timelines
Stop all active timelines and immediately kill physical motor vibration:
import { stop } from 'react-native-haptic-timeline';
// Instantly stops timelines and cancels physical vibrations
const handleCancelClick = () => {
stop();
};🎨 Custom Patterns & Step Durations
A custom pattern is an array of step objects, defining the haptic type, the delay before the step, and an optional duration override (supported by the fallback vibration engine):
import { trigger } from 'react-native-haptic-timeline';
// A custom rhythmic sequence with duration overrides
trigger([
{ type: 'heavy', delay: 0, duration: 200 }, // Vibrate for 200ms
{ type: 'light', delay: 150, duration: 50 }, // Vibrate for 50ms
{ type: 'light', delay: 75 }, // Standard light vibration
{ type: 'heavy', delay: 150 }
]);Hook Usage with Auto-Cleanup
Always use the useHapticPatterns hook inside dynamic UI components (like modals or navigating screens). It tracks local context and automatically stops pending timers and cancels active vibrations if the hosting component unmounts mid-pattern.
import React from 'react';
import { Button } from 'react-native';
import { useHapticPatterns } from 'react-native-haptic-timeline';
const LikeButton = () => {
const { trigger, stop } = useHapticPatterns();
return (
<>
<Button
title="Like Post"
onPress={() => trigger('heartbeat', { repeat: 2 })}
/>
<Button
title="Cancel Haptics"
onPress={() => stop()}
/>
</>
);
};🎚️ Global Toggle Control
Easily toggle haptic vibration globally across your entire application (ideal for settings screens):
import { setHapticsEnabled, isHapticsEnabled } from 'react-native-haptic-timeline';
// Disable haptics globally
setHapticsEnabled(false);
// Query state
console.log(isHapticsEnabled()); // false📋 Available Preset Patterns
| Preset Pattern | Description | Sequence Timeline |
| :--- | :--- | :--- |
| heartbeat | A double rhythmic pulse simulating a heartbeat. | light ➡️ medium (150ms) |
| success-double | Success notification followed by a light confirmation tick. | success ➡️ light (250ms) |
| error-triple | Strong warning notification followed by two heavy alert pulses. | error ➡️ heavy (250ms) ➡️ heavy (150ms) |
| warning-pulse | Caution alert followed by a delayed medium pulse. | warning ➡️ medium (200ms) |
| soft-tick | Minimal tactile response for selection. | selection (0ms) |
| rapid-success | High-frequency succession of light ticks. | light ➡️ light (80ms) ➡️ light (80ms) |
| ocean-wave | Wave-like effect ramping up and down in weight. | light ➡️ medium (100ms) ➡️ heavy (100ms) ➡️ medium (150ms) ➡️ light (150ms) |
📜 License
MIT
