React Native Theme TransitionReact Native Theme Transition
Examples

Theme Button

Simple cycling button that uses setTheme directly — no selection tracking needed.

A button that cycles through themes. Since the button's visual appearance doesn't change on theme switch (it just shows a static label), no selection tracking is needed.

import { Text, Pressable } from 'react-native';
import { useTheme } from '@/lib/theme';

const CYCLE = ['light', 'dark'] as const;

export function ThemeButton() {
  const { colors, name, setTheme, isTransitioning } = useTheme();
  const nextIndex = (CYCLE.indexOf(name as typeof CYCLE[number]) + 1) % CYCLE.length;

  return (
    <Pressable
      onPress={() => setTheme(CYCLE[nextIndex])}
      disabled={isTransitioning}
      style={{
        padding: 16,
        borderRadius: 12,
        alignItems: 'center',
        backgroundColor: colors.primary,
      }}
    >
      <Text style={{ color: '#fff', fontSize: 16, fontWeight: '600' }}>
        Switch theme
      </Text>
    </Pressable>
  );
}

Do not change styles based on isTransitioning (e.g., opacity: isTransitioning ? 0.5 : 1). The screenshot captures the current visual state — if the button is dimmed when the screenshot is taken, the cross-fade will blend the dimmed state with the new theme, producing a visible flash.

When to use this pattern

This is the only pattern where you can call setTheme directly. It works because:

  • The button's label is static ("Switch theme") — it doesn't change before the screenshot
  • There's no visual indicator (highlight, checkmark, thumb) that needs to be updated before the screenshot

If you add a visual indicator to the button (e.g., a colored border on the active theme), switch to useTheme({}) and use select() instead.

On this page