Haptic Feedback
Tactile feedback patterns that complement visual and audio cues. All Sitka components respect the haptic taxonomy for consistent physical feeling across platforms.
Categories
Haptics convey meaning through vibration patterns and intensity. Sitka provides a cross-platform mapping so a notification-success feels equally affirming on iOS, Android, and the web (where supported).
Impact3 tokens
Physical strikes and collisions; conveys weight, solidity, and confirmation of direct manipulation.
haptic.impact.lightLight tap, gentle confirmation, selection change
Picking from list, scroll end
haptic.impact.mediumMedium-impact collision, standard action feedback
Button press, toggle switch
haptic.impact.heavyHeavy impact, strong physical feel
Destructive action confirmation, door knock
Platform API mapping
UIImpactFeedbackGenerator(style: .medium)Vibrator.vibrate(VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK))navigator.vibrate(15)Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium)Notification3 tokens
Event-driven signals for attention, success, warning, or error states.
haptic.notification.successPositive completion, task succeeded
Form submitted, upload complete
haptic.notification.warningNon-critical issue needs attention
Validation warning, battery low
haptic.notification.errorCritical failure, action blocked
Network error, validation failed
Platform API mapping
UINotificationFeedbackGeneratorVibrator.vibrate(VibrationEffect.createPredefined(VibrationEffect.EFFECT_DOUBLE_CLICK))navigator.vibrate([50, 50, 50])Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success)Selection2 tokens
Continuous tactile feedback during manipulation tasks like picking or adjusting.
haptic.selection.clickSnap-to-grid or discrete selection tick
Picker wheel selection, slider increment
haptic.selection.pickItem chosen from set
Dropdown selection, segmented control change
Platform API mapping
UISelectionFeedbackGeneratorVibrator.vibrate(VibrationEffect.createPredefined(VibrationEffect.EFFECT_TICK))navigator.vibrate(8)Haptics.selectionAsync()Best practices
Don't overuse
Every haptic should mean something. Avoid haptics for routine interactions; reserve for confirmation, error, or delight moments.
Respect accessibility
Users can disable haptics system-wide. Your app must work without them — never gate functionality behind haptic feedback.
Keep it brief
Haptics should last 10–50ms. Longer vibrations feel like buzzing and are annoying.
Sync with visual/audio
Haptics should align with the moment of action completion. Delay breaks the illusion of causality.
Test on device
Simulators cannot accurately reproduce haptics. Test on real hardware to verify intensity and duration.
Use platform defaults
Don't invent custom patterns unless your brand requires it. System patterns are already learned by users.
Implementation
Sitka exposes a unified haptic utility that maps to platform-native APIs. Use it in your interaction handlers to keep tactile feedback consistent.
import * as Haptics from 'expo-haptics';
import { Platform } from 'react-native';
export type HapticType =
| "impact.light" | "impact.medium" | "impact.heavy"
| "notification.success" | "notification.warning" | "notification.error"
| "selection.click" | "selection.pick";
export function useHaptic() {
const trigger = (type: HapticType) => {
if (Platform.OS === 'ios' || Platform.OS === 'android') {
const [category, variant] = type.split('.') as [HapticCategory, string];
// Maps to expo-haptics or react-native-haptic-feedback
Haptics[category]?.[variant]?.();
} else if (navigator.vibrate) {
// Web fallback
const patterns: Record<HapticType, number[]> = {
"impact.light": [8],
"impact.medium": [15],
"impact.heavy": [25],
"notification.success": [20, 50, 20],
"notification.error": [30, 30, 30],
};
navigator.vibrate(patterns[type]);
}
};
return { trigger };
}Usage
const { trigger } = useHaptic();
// Button press
<Button
onPress={() => {
trigger("impact.medium");
handleSubmit();
}}
/>
// Error state
if (error) {
trigger("notification.error");
}
// Selection in picker
trigger("selection.click");