Back to Components
📳

Native Haptics

Advanced

A lightweight, zero-dependency implementation of haptic feedback using direct native code for iOS (UIImpactFeedbackGenerator) and Android (Vibrator/HapticFeedbackConstants). Perfect for avoiding heavy external libraries.

Utilityv1.0.0Updated 2026-02-04

Installation

1

Copy NativeHaptics.ts to your project

2

Copy android/HapticsModule.kt & HapticsPackage.kt to android/app/src/main/java/com/yourpackage/haptics/

3

Copy ios/Haptics.swift & Haptics.m to ios/YourAppName/

4

Link the package in MainApplication.kt (Android)

5

Ensure Swift bridging header exists (iOS)

⚠️ Native Setup Required:

  • No npm install required!

Source Code

NativeHaptics.tsTS
import { NativeModules, Platform } from 'react-native';

const { Haptics } = NativeModules;

// Safety check
if (!Haptics) {
    console.warn('[Haptics] Native module not linked');
}

// Low-level wrappers
const impact = (style: 'light' | 'medium' | 'heavy' | 'soft' | 'rigid' = 'medium') => {
    Haptics?.impact(style);
};

const selection = () => {
    Haptics?.selection();
};

const notification = (type: 'success' | 'warning' | 'error' = 'success') => {
    Haptics?.notification(type);
};

// Utils
export const triggerHaptic = () => {
    // subtle feedback (welcome icons, light UI)
    impact(Platform.OS === 'ios' ? 'soft' : 'light');
};

export const triggerSelectionHaptic = () => {
    // perfect for tabs, pickers
    selection();
};

export const triggerMediumHaptic = () => {
    // buttons, bottom nav, primary actions
    impact('medium');
};

export const triggerSuccessHaptic = () => {
    notification('success');
};

export const triggerErrorHaptic = () => {
    notification('error');
};
android/HapticsModule.ktKT
package com.travelogger.haptics

import android.content.Context
import android.os.Build
import android.os.VibrationEffect
import android.os.Vibrator
import android.view.HapticFeedbackConstants
import android.view.View
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.ReactContextBaseJavaModule
import com.facebook.react.bridge.ReactMethod

class HapticsModule(
  private val reactContext: ReactApplicationContext
) : ReactContextBaseJavaModule(reactContext) {

  override fun getName(): String = "Haptics"

  private fun vibrate(duration: Long, amplitude: Int) {
    val vibrator =
      reactContext.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
      vibrator.vibrate(
        VibrationEffect.createOneShot(duration, amplitude)
      )
    } else {
      @Suppress("DEPRECATION")
      vibrator.vibrate(duration)
    }
  }

  @ReactMethod
  fun impact(style: String) {
    when (style) {
      "light" -> vibrate(10, 50)
      "medium" -> vibrate(20, 120)
      "heavy" -> vibrate(30, 255)
      else -> vibrate(15, 100)
    }
  }

  @ReactMethod
  fun selection() {
    val activity = reactContext.currentActivity ?: return

    activity.window.decorView.performHapticFeedback(
      HapticFeedbackConstants.KEYBOARD_TAP,
      HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING
    )
  }

  @ReactMethod
  fun notification(type: String) {
    when (type) {
      "success" -> vibrate(40, 180)
      "warning" -> vibrate(60, 200)
      "error" -> vibrate(80, 255)
    }
  }
}
android/HapticsPackage.ktKT
package com.travelogger.haptics

import com.facebook.react.ReactPackage
import com.facebook.react.bridge.NativeModule
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.uimanager.ViewManager

class HapticsPackage : ReactPackage {

  override fun createNativeModules(
    reactContext: ReactApplicationContext
  ): List<NativeModule> {
    return listOf(HapticsModule(reactContext))
  }

  override fun createViewManagers(
    reactContext: ReactApplicationContext
  ): List<ViewManager<*, *>> = emptyList()
}
ios/Haptics.swiftSWIFT
import UIKit

@objc(Haptics)
class Haptics: NSObject {

  @objc static func requiresMainQueueSetup() -> Bool {
    return true
  }

  @objc func impact(_ style: NSString) {
    DispatchQueue.main.async {
      let feedbackStyle: UIImpactFeedbackGenerator.FeedbackStyle

      switch style {
      case "light":
        feedbackStyle = .light
      case "medium":
        feedbackStyle = .medium
      case "heavy":
        feedbackStyle = .heavy
      case "soft":
        if #available(iOS 13.0, *) {
          feedbackStyle = .soft
        } else {
          feedbackStyle = .light
        }
      case "rigid":
        if #available(iOS 13.0, *) {
          feedbackStyle = .rigid
        } else {
          feedbackStyle = .medium
        }
      default:
        feedbackStyle = .medium
      }

      let generator = UIImpactFeedbackGenerator(style: feedbackStyle)
      generator.prepare()
      generator.impactOccurred()
    }
  }

  @objc func selection() {
    DispatchQueue.main.async {
      let generator = UISelectionFeedbackGenerator()
      generator.prepare()
      generator.selectionChanged()
    }
  }

  @objc func notification(_ type: NSString) {
    DispatchQueue.main.async {
      let generator = UINotificationFeedbackGenerator()
      generator.prepare()

      switch type {
      case "success":
        generator.notificationOccurred(.success)
      case "warning":
        generator.notificationOccurred(.warning)
      case "error":
        generator.notificationOccurred(.error)
      default:
        generator.notificationOccurred(.success)
      }
    }
  }
}
ios/Haptics.mM
#import <React/RCTBridgeModule.h>

@interface RCT_EXTERN_MODULE(Haptics, NSObject)

RCT_EXTERN_METHOD(impact:(NSString *)style)
RCT_EXTERN_METHOD(selection)
RCT_EXTERN_METHOD(notification:(NSString *)type)

@end

Usage Examples

Basic Usage

Trigger haptics on button press

Example 1
import { triggerSelectionHaptic } from './NativeHaptics';

<TouchableOpacity onPress={triggerSelectionHaptic}>
  <Text>Press Me</Text>
</TouchableOpacity>

Props

PropTypeDefaultDescription
triggerHapticfunction-Triggers a light/soft impact
triggerSelectionHapticfunction-Triggers a selection feedback (good for pickers/tabs)
triggerSuccessHapticfunction-Triggers a success notification pattern
triggerErrorHapticfunction-Triggers an error notification pattern

Features

  • Zero npm dependencies
  • Direct Native Access
  • iOS High Precision Haptics
  • Android Vibration Fallback
  • Type-safe Wrapper
  • Custom patterns supported

Dependencies

Required:

None