Troubleshooting
Common issues, causes, and solutions.
iOS picker flickering
Symptom: On iOS, a theme picker with highlighted buttons flickers during the cross-fade — the selection indicator alternates between old and new positions.
Cause: Calling setSelected() and setTheme() in the same event handler doesn't
give React enough time to paint the selection before the screenshot captures.
Fix: Use useTheme({ initialSelection }):
const { selected, select, colors, isTransitioning } =
useTheme({ initialSelection: 'system' });
<Pressable onPress={() => select(option)} disabled={isTransitioning}>See Theme Picker example for the complete pattern.
Native Switch flickers
Symptom: On iOS, a native <Switch> thumb appears mid-slide in the screenshot.
Cause: iOS's UISwitch runs a ~250ms Core Animation with no completion callback.
react-native-view-shot captures the on-screen visual state including the thumb mid-slide.
Fix: Use a custom toggle with useTheme({}) and
plain React styles (no Reanimated).
Overlay stays visible / app seems frozen
Symptom: The screen appears frozen — touches don't work.
Check:
- Look for
[react-native-theme-transition] Failed to capture screenshotin the console - Verify
react-native-view-shotis properly installed (npx expo doctor) - Ensure the root
Viewhascollapsable={false}(set internally)
Flash on theme change (no animation)
Causes:
animated: false— Check if you're passing{ animated: false }in options- Provider placement —
ThemeTransitionProvidermust wrap the full visible tree react-native-view-shotnot installed —captureRefthrows, falls back to instant switch- Missing worklets plugin —
react-native-worklets/pluginmust be the last plugin inbabel.config.js
Fix: Verify provider placement, peer dependencies, and babel config. Restart with npx expo start -c.
Duplicate plugin/preset detected
Symptom: SyntaxError: Duplicate plugin/preset detected.
Cause: From Expo SDK 55, babel-preset-expo already includes react-native-reanimated/plugin.
Fix: On SDK 55+, remove 'react-native-reanimated/plugin' from your plugins:
plugins: [
// SDK 55+: babel-preset-expo already includes reanimated/plugin
'react-native-worklets/plugin', // must be last
],Cannot find module 'babel-preset-expo'
Cause: Expo SDK 55 blank templates no longer include babel-preset-expo as a dependency.
Fix:
npx expo install babel-preset-expoSystem theme not following OS
Causes:
- System mode not activated — Verify
initialTheme="system"orsetTheme('system') - Manual setTheme overrides —
setTheme('dark')exits system mode - Missing
systemThemeMap— Required for custom theme names - iOS Simulator — Use
Cmd+Shift+Ato toggle appearance
Type errors on colors
Symptom: Property 'myToken' does not exist on type '{ ... }'
Fix: Ensure all themes share identical keys:
const light = { bg: '#fff', text: '#000' };
const dark: Record<keyof typeof light, string> = { bg: '#000', text: '#fff' };Theme changes but no animation plays
Causes:
duration: 0— Set a positive durationanimated: false— Check allsetThemecall sites- System-driven in background — Background changes use instant switch by design
- Bridge firing on mount — Normal behavior for first load
setTheme does nothing
Causes:
- Same theme —
setTheme('dark')when already dark returnsfalse - During transition — Returns
false, system mode is not activated. Retry afterisTransitioningbecomesfalse - System mode dedup —
setTheme('system')when OS-resolved matches current activates system mode but no visual change
Double transition on app start
Cause: initialTheme resolves to one theme, then a bridge fires setTheme with a different stored preference.
Fix: Pass the stored preference as initialTheme:
import { useThemeStore } from '@/stores/theme-store';
const themePreference = useThemeStore((s) => s.themePreference);
<ThemeTransitionProvider initialTheme={themePreference}>Android: capture returns blank
Causes:
collapsablenot set — The root View needscollapsable={false}(set internally)- Hardware acceleration issues — The library falls back to instant switch automatically
- View not fully rendered — The library waits frames before capture to prevent this
Error messages reference
| Error | Cause |
|---|---|
themes must contain at least one theme | Empty themes object |
"system" is a reserved name | Theme named 'system' — rename it |
different token keys | Theme keys don't match across themes |
systemThemeMap maps to non-existent theme | Typo in systemThemeMap values |
initialTheme resolved to non-existent theme | 'system' + custom names without systemThemeMap |
useTheme must be used inside a ThemeTransitionProvider | Hook called outside provider tree |