npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-native-haptic-timeline

v1.0.1

Published

Meaningful haptic feedback sequences for React Native (Expo & CLI)

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 useHapticPatterns hook automatically cancels pending vibration timers if the hosting component unmounts.
  • Zero-Config Fallback: Automatically falls back to React Native's standard Vibration API 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