Haptics
Using expo-haptics for tactile feedback on button presses, success confirmations, and error alerts.
Haptics
Haptic feedback adds a physical dimension to your app's interactions. ScaleRocket Mobile uses expo-haptics to provide tactile responses for button presses, success/error states, and UI transitions.
Setup
npx expo install expo-hapticsNote: Haptics require a physical device. Simulators and emulators do not vibrate.
Basic Usage
import * as Haptics from "expo-haptics";
// Light tap — button press, toggle
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
// Medium tap — selection change
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium);
// Heavy tap — significant action
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Heavy);Feedback Types
expo-haptics provides three categories of feedback:
Impact Feedback
Physical tap sensation with varying intensity:
// Light — subtle, for frequent interactions
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
// Medium — moderate, for selections
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium);
// Heavy — strong, for important actions
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Heavy);Notification Feedback
Semantic feedback tied to outcomes:
// Success — action completed
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success);
// Warning — caution needed
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Warning);
// Error — action failed
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Error);Selection Feedback
For picker wheels and selection changes:
Haptics.selectionAsync();When to Use Haptics
| Interaction | Haptic Type | Why |
|---|---|---|
| Button press | Impact.Light | Confirm the tap registered |
| Toggle switch | Impact.Light | Physical click feel |
| Delete action | Impact.Heavy | Emphasize destructive action |
| Form submitted | Notification.Success | Confirm completion |
| Error shown | Notification.Error | Alert the user |
| Pull to refresh | Impact.Medium | Threshold reached |
| Picker scroll | Selection | Each option change |
| Long press | Impact.Heavy | Context menu trigger |
Integration with Components
Haptic Button
Add haptics to the Button component:
import * as Haptics from "expo-haptics";
function HapticButton({ onPress, haptic = true, ...props }: ButtonProps) {
const handlePress = () => {
if (haptic) {
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
}
onPress?.();
};
return <Button {...props} onPress={handlePress} />;
}Haptic Tab Bar
Add feedback when switching tabs:
// app/(tabs)/_layout.tsx
<Tabs
screenListeners={{
tabPress: () => {
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
},
}}
>
{/* Tab screens */}
</Tabs>Delete Confirmation
async function handleDelete() {
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Warning);
Alert.alert("Delete Item", "This cannot be undone.", [
{ text: "Cancel", style: "cancel" },
{
text: "Delete",
style: "destructive",
onPress: async () => {
await deleteItem();
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success);
},
},
]);
}Custom Hook
Create a reusable haptics hook:
import * as Haptics from "expo-haptics";
import { Platform } from "react-native";
export function useHaptics() {
const isDevice = Platform.OS !== "web";
return {
light: () => isDevice && Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light),
medium: () => isDevice && Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium),
heavy: () => isDevice && Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Heavy),
success: () => isDevice && Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success),
error: () => isDevice && Haptics.notificationAsync(Haptics.NotificationFeedbackType.Error),
warning: () => isDevice && Haptics.notificationAsync(Haptics.NotificationFeedbackType.Warning),
selection: () => isDevice && Haptics.selectionAsync(),
};
}Usage:
function MyComponent() {
const haptics = useHaptics();
return (
<Button title="Save" onPress={() => {
haptics.light();
handleSave();
}} />
);
}Best Practices
- Don't overdo it — Too much haptic feedback becomes annoying
- Match intensity to importance — Light for routine, heavy for significant
- Skip on web — Check platform before calling haptics
- Respect user settings — iOS system haptics settings are respected automatically
- Test on real devices — Simulators cannot produce haptic feedback