Skip to main content

expo-haptics

Version: 55.0.6 Provides access to the system’s haptics engine on iOS, vibration effects on Android, and Web Vibration API on web.

Installation

npx expo install expo-haptics

Usage

import * as Haptics from 'expo-haptics';

// Light impact
await Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);

// Success notification
await Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success);

// Selection feedback
await Haptics.selectionAsync();

API Reference

Impact Feedback

Haptics.impactAsync(style)
(style: ImpactFeedbackStyle) => Promise<void>
Triggers impact haptic feedbackStyles:
  • Haptics.ImpactFeedbackStyle.Light
  • Haptics.ImpactFeedbackStyle.Medium
  • Haptics.ImpactFeedbackStyle.Heavy
  • Haptics.ImpactFeedbackStyle.Rigid (iOS 13+)
  • Haptics.ImpactFeedbackStyle.Soft (iOS 13+)
await Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium);

Notification Feedback

Haptics.notificationAsync(type)
(type: NotificationFeedbackType) => Promise<void>
Triggers notification haptic feedbackTypes:
  • Haptics.NotificationFeedbackType.Success
  • Haptics.NotificationFeedbackType.Warning
  • Haptics.NotificationFeedbackType.Error
await Haptics.notificationAsync(
  Haptics.NotificationFeedbackType.Success
);

Selection Feedback

Haptics.selectionAsync()
() => Promise<void>
Triggers selection change haptic feedback
// Use when user changes a selection (e.g., picker wheel)
await Haptics.selectionAsync();

Examples

Button Press Feedback

import * as Haptics from 'expo-haptics';
import { TouchableOpacity, Text } from 'react-native';

function HapticButton() {
  const handlePress = async () => {
    await Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium);
    // Handle button action
  };

  return (
    <TouchableOpacity onPress={handlePress}>
      <Text>Press Me</Text>
    </TouchableOpacity>
  );
}

Form Validation Feedback

import * as Haptics from 'expo-haptics';
import { useState } from 'react';
import { TextInput, Button } from 'react-native';

function Form() {
  const [email, setEmail] = useState('');

  const handleSubmit = async () => {
    if (!email.includes('@')) {
      await Haptics.notificationAsync(
        Haptics.NotificationFeedbackType.Error
      );
      alert('Invalid email');
      return;
    }

    await Haptics.notificationAsync(
      Haptics.NotificationFeedbackType.Success
    );
    // Submit form
  };

  return (
    <>
      <TextInput value={email} onChangeText={setEmail} />
      <Button title="Submit" onPress={handleSubmit} />
    </>
  );
}

Picker Selection

import * as Haptics from 'expo-haptics';
import { useState } from 'react';
import { Picker } from '@react-native-picker/picker';

function PickerWithHaptics() {
  const [selected, setSelected] = useState('option1');

  const handleValueChange = async (value: string) => {
    await Haptics.selectionAsync();
    setSelected(value);
  };

  return (
    <Picker selectedValue={selected} onValueChange={handleValueChange}>
      <Picker.Item label="Option 1" value="option1" />
      <Picker.Item label="Option 2" value="option2" />
      <Picker.Item label="Option 3" value="option3" />
    </Picker>
  );
}

Different Impact Levels

import * as Haptics from 'expo-haptics';
import { View, Button } from 'react-native';

function HapticDemo() {
  return (
    <View style={{ gap: 10 }}>
      <Button
        title="Light Impact"
        onPress={() => Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light)}
      />
      <Button
        title="Medium Impact"
        onPress={() => Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium)}
      />
      <Button
        title="Heavy Impact"
        onPress={() => Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Heavy)}
      />
      <Button
        title="Success"
        onPress={() => Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success)}
      />
      <Button
        title="Warning"
        onPress={() => Haptics.notificationAsync(Haptics.NotificationFeedbackType.Warning)}
      />
      <Button
        title="Error"
        onPress={() => Haptics.notificationAsync(Haptics.NotificationFeedbackType.Error)}
      />
    </View>
  );
}

Platform Support

PlatformHapticsVibration
iOS✅ UIFeedbackGenerator
Android✅ VibrationEffect
Web✅ Vibration API
iOS: Uses UIImpactFeedbackGenerator, UINotificationFeedbackGenerator, and UISelectionFeedbackGeneratorAndroid: Uses VibrationEffect (API 26+) or Vibrator for older versionsWeb: Uses the Vibration API where supported

Best Practices

  1. Use Sparingly: Overuse can be annoying
  2. Match Interaction: Use appropriate feedback type for the interaction
  3. Respect Settings: Haptics honor system settings (vibration off, etc.)
  4. Light for UI: Use Light impact for most UI interactions
  5. Notifications for States: Use notification feedback for success/error states

Resources