Skip to content

Theme Switching

Implement smooth, user-friendly theme switching with animations, persistence, and advanced transition effects. RNC Theme provides powerful tools for creating seamless theme experiences.

Theme switching in RNC Theme supports:

Mode Switching

Switch between light, dark, and system modes with automatic detection.

Preset Switching

Change between registered theme presets instantly.

Smooth Animations

Animated transitions with customizable duration and easing.

Persistence

Automatic saving and restoration of user theme preferences.

Targeted Updates

Update specific theme properties without full theme replacement.

Performance

Optimized switching with minimal re-renders and smooth performance.

import { useTheme } from 'rnc-theme';
function ThemeModeToggle() {
const {
themeMode,
setThemeMode,
isDark,
} = useTheme();
const toggleMode = () => {
setThemeMode(isDark ? 'light' : 'dark');
};
return (
<TouchableOpacity onPress={toggleMode}>
<Text>{isDark ? '☀️' : '🌙'}</Text>
<Text>{themeMode} mode</Text>
</TouchableOpacity>
);
}
import { useTheme } from 'rnc-theme';
function ThemeCustomizer() {
const { updateCustomTheme } = useTheme();
const preset = {
colors: {
primary: 'blue',
background: 'white',
},
// ...rest
};
const applyBrandTheme = () => {
updateCustomTheme(
// ...preset
);
};
return (
<Button onPress={applyBrandTheme}>
Apply Brand Theme
</Button>
);
}

updateCustomTheme is used to apply custom theme presets to your app. You can create a theme preset object with the desired color, spacing, and other theme properties, and then pass it to updateCustomTheme to apply it to your app.

You can simply use <ToggleMode/> component to switch between light and dark modes.

import { View } from 'react-native';
import { ToggleMode } from 'rnc-theme';
function ThemeSwitcher() {
return (
<View>
<ToggleMode />
</View>
);
}

You can use <ThemeManager/> component to manage theme presets and switch between them.

import { useMemo } from 'react';
import { ThemeManager, Box } from 'rnc-theme';
function ThemeManagerComponent() {
const materialThemeConfig: CustomThemeConfigFactory = useMemo(
() => (isDark: boolean) => ({
colors: {
primary: '#6200EE',
secondary: '#03DAC6',
background: isDark ? '#121212' : '#FFFFFF',
surface: isDark ? '#1E1E1E' : '#FFFFFF',
text: isDark ? '#FFFFFF' : '#000000',
textSecondary: isDark ? '#B3B3B3' : '#757575',
border: isDark ? '#2C2C2C' : '#E0E0E0',
error: '#B00020',
warning: '#FF6F00',
success: '#00C853',
info: '#2962FF',
muted: isDark ? '#666666' : '#999999',
accent: '#6200EE',
destructive: '#B00020',
},
components: {
height: {
xs: 32,
sm: 36,
md: 40,
lg: 44,
xl: 48,
},
padding: {
xs: 8,
sm: 12,
md: 16,
lg: 20,
xl: 24,
},
borderRadius: {
xs: 4,
sm: 4,
md: 4,
lg: 8,
xl: 12,
full: 9999,
},
},
spacing: {
xs: 4,
sm: 8,
md: 16,
lg: 24,
xl: 32,
xxl: 48,
},
typography: {
caption: { fontSize: 10, lineHeight: 14, fontWeight: '400' },
small: { fontSize: 12, lineHeight: 16, fontWeight: '400' },
body: { fontSize: 16, lineHeight: 24, fontWeight: '400' },
subtitle: { fontSize: 18, lineHeight: 26, fontWeight: '500' },
title: { fontSize: 20, lineHeight: 28, fontWeight: '600' },
heading: { fontSize: 24, lineHeight: 32, fontWeight: '700' },
},
fontSizes: {
xs: 12,
sm: 14,
md: 16,
lg: 18,
xl: 20,
xxl: 24,
},
}),
[]
);
const neonThemeConfig: CustomThemeConfigFactory = useMemo(
() => (isDark: boolean) => ({
colors: {
primary: '#00FFFF',
secondary: '#FF00FF',
background: isDark ? '#0a0a0a' : '#f0f0f0',
surface: isDark ? '#1a1a1a' : '#ffffff',
text: isDark ? '#00FFFF' : '#333333',
textSecondary: isDark ? '#FF00FF' : '#666666',
border: isDark ? '#00FFFF' : '#e0e0e0',
error: '#FF0040',
warning: '#FFFF00',
success: '#00FF40',
info: '#4080FF',
muted: isDark ? '#666666' : '#999999',
accent: '#FF00FF',
destructive: '#FF0040',
},
components: {
height: {
xs: 32,
sm: 36,
md: 40,
lg: 44,
xl: 48,
},
padding: {
xs: 8,
sm: 12,
md: 16,
lg: 20,
xl: 24,
},
borderRadius: {
xs: 2,
sm: 2,
md: 4,
lg: 8,
xl: 16,
full: 9999,
},
},
spacing: {
xs: 4,
sm: 8,
md: 16,
lg: 24,
xl: 32,
xxl: 48,
},
typography: {
caption: { fontSize: 10, lineHeight: 14, fontWeight: '400' },
small: { fontSize: 12, lineHeight: 16, fontWeight: '400' },
body: { fontSize: 16, lineHeight: 24, fontWeight: '400' },
subtitle: { fontSize: 18, lineHeight: 26, fontWeight: '500' },
title: { fontSize: 20, lineHeight: 28, fontWeight: '600' },
heading: { fontSize: 24, lineHeight: 32, fontWeight: '700' },
},
fontSizes: {
xs: 12,
sm: 14,
md: 16,
lg: 18,
xl: 20,
xxl: 24,
},
}),
[]
);
const themePresets: ThemePresetConfig[] = useMemo(
() => [
{
key: 'material',
label: 'Material Design',
config: materialThemeConfig,
},
{
key: 'neon',
label: 'Neon Glow',
config: neonThemeConfig,
},
],
[materialThemeConfig, neonThemeConfig]
);
const handleThemeApplied = (theme: string) => {
console.log(`Theme applied: ${theme}`);
};
const handleThemePreview = (theme: string) => {
console.log(`Theme previewed: ${theme}`);
};
return (
<Box>
<ThemeManager
themePresets={themePresets}
initialTheme="default"
onThemeApplied={handleThemeApplied}
onThemePreview={handleThemePreview}
>
{/* Demo content for default version */}
<Card style={styles.demoCard}>
<CardHeader title="Demo Content - Default" />
<CardContent>
<Typography variant="body" style={styles.demoText}>
This is the default ThemeManager with standard labels and
messages.
</Typography
<View style={styles.buttonContainer}>
<Button variant="primary" style={styles.demoButton}>
<ButtonText>Primary Button</ButtonText>
</Button
<Button variant="secondary" style={styles.demoButton}>
<ButtonText>Secondary Button</ButtonText>
</Button
<Button variant="outline" style={styles.demoButton}>
<ButtonText>Outline Button</ButtonText>
</Button>
</View
<View style={styles.colorDemo}>
<View
style={[
styles.colorBox,
{ backgroundColor: theme.colors.primary },
]}
/>
<View
style={[
styles.colorBox,
{ backgroundColor: theme.colors.secondary },
]}
/>
<View
style={[
styles.colorBox,
{ backgroundColor: theme.colors.accent },
]}
/>
<View
style={[
styles.colorBox,
{ backgroundColor: theme.colors.success },
]}
/>
<View
style={[
styles.colorBox,
{ backgroundColor: theme.colors.warning },
]}
/>
<View
style={[
styles.colorBox,
{ backgroundColor: theme.colors.error },
]}
/>
</View>
</CardContent>
</Card>
</ThemeManager>
</Box>
);
}

Using preset builtin, import { presetThemes } from 'rnc-theme'

import { presetThemes } from 'rnc-theme'
export default function Component() {
const handleThemeApplied = (theme: string) => {
console.log(`Theme applied: ${theme}`);
};
const handleThemePreview = (theme: string) => {
console.log(`Theme previewed: ${theme}`);
};
return (
<ThemeManager
themePresets={presetThemes}
initialTheme="default"
onThemeApplied={handleThemeApplied}
onThemePreview={handleThemePreview}
>
{/* children */}
</ThemeManager>
)
}