Recipes
Haptic Feedback & Analytics
Add haptic feedback and analytics tracking to theme transitions.
Haptic feedback
On every animated transition (config-level)
import * as Haptics from 'expo-haptics';
export const { ThemeTransitionProvider, useTheme } = createThemeTransition({
themes: { light, dark },
onTransitionStart: () => {
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium);
},
});On a specific button only (per-call)
function ThemeToggle() {
const { name, setTheme } = useTheme();
return (
<Pressable onPress={() => {
setTheme(name === 'light' ? 'dark' : 'light', {
onTransitionStart: () => {
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium);
},
});
}}>
<Text>Toggle</Text>
</Pressable>
);
}Analytics
Use onThemeChange to track every theme change (animated, instant, system-driven):
export const { ThemeTransitionProvider, useTheme } = createThemeTransition({
themes: { light, dark },
onThemeChange: (name) => {
analytics.track('theme_changed', { theme: name });
},
});onThemeChange is the only callback guaranteed to fire for every theme change.
onTransitionStart and onTransitionEnd only fire for animated transitions.
Disable UI during transitions
Disable a button
<Pressable
onPress={() => setTheme('dark')}
disabled={isTransitioning}
>
<Text>Switch theme</Text>
</Pressable>Do not change styles based on isTransitioning (e.g., opacity). The screenshot captures
the current visual state — style changes will bleed into the cross-fade.
Defer expensive renders
function HeavyChart() {
const { isTransitioning, colors } = useTheme();
if (isTransitioning) {
return <View style={{ height: 200, backgroundColor: colors.card }} />;
}
return <ExpensiveChartComponent colors={colors} />;
}