KJ-GM/theme-csx
๐ Powerful theming framework for React Native with dark mode, dynamic colors, and persistence.
โญ๏ธ Enjoying the library? Support it with a star on GitHub โ thank you!
๐งช Check out the Demo App Showcase to see
theme-csxin action.
โจ Features
- โก๏ธ Light / Dark / System theme support
- ๐ Dynamic iOS color adaptation
- ๐พ MMKV-based persistent theme storage
- ๐ง Memoized themed styles with createThemedStyles
- ๐ Type-safe access to theme tokens (with autocomplete)
- ๐ Scalable for monorepos and multi-app setups
- ๐งฉ Extendable (spacing, typography, shadows, etc.)
โ iOS: theme changes apply instantly
๐ Android: theme changes apply on app restart
๐ฆ Installation
# npm
npm install theme-csx
# yarn
yarn add theme-csx
# pnpm
pnpm add theme-csx๐ Quick Start
1. Define your own theme
Create your own theme object.
โ colors.light is required and defines the base color palette.
โ colors.dark is optional, but must only override keys already defined in colors.light.
๐จ Everything else is optional and fully customizable โ feel free to add anything like spacing, typography, radius, etc.
// theme/theme.ts
export const theme = {
colors: {
light: {
background: '#ffffff',
text: '#111111',
},
dark: {
background: '#000000', // โ
valid override
text: '#ffffff', // โ
valid override
// error if an unknown key like "accent" is added here!
},
},
spacing: {
sm: 8,
md: 16,
lg: 24,
},
// Add any other tokens you want (typography, radius, etc.)
};2. Create your theme system
Use createAppTheme() to initialize your theming system.
๐จ Critical:
createAppTheme()must be called only once in your entire app.
Calling it multiple times can cause unexpected behavior & theme conflicts.
You can enable persistent theme mode storage (optional) by setting { storage: true }.
โ ๏ธ Requiresreact-native-mmkvif storage is enabled.
// theme/index.ts
import { createAppTheme } from 'theme-csx';
import { theme } from './theme';
export const {
AppThemeProvider,
useTheme,
useThemeMode,
useSetThemeMode,
useResetThemeMode,
useToggleThemeMode,
useCycleThemeMode,
createThemedStyles,
createStaticStyles,
useResolveColor, // NEW
types,
} = createAppTheme(theme, {
storage: true, // Optional: disables persistence if omitted or set to false
storageKey: 'theme-mode', // NEW: custom key name for storage
storageInstance: myMMKVInstance, // NEW: optional external MMKV instance
});
export type Theme = typeof types.Theme;
export type ThemeMode = typeof types.ThemeMode;3. Wrap your app
Wrap your app with AppThemeProvider and you are all set ๐.
// App.tsx
import { AppThemeProvider } from '@theme';
export default function App() {
return (
<AppThemeProvider>
{/* your app code */}
</AppThemeProvider>
);
}๐จ Usage
- Access current theme
import { useTheme } from '@theme';
const MyComponent = () => {
const theme = useTheme();
return <View style={{ backgroundColor: theme.colors.background }} />;
};- Themed & Static Styles (Responsive vs Fixed)
import { View, Text } from 'react-native';
import { createThemedStyles, createStaticStyles } from '@theme';
// ๐จ Styles that respond to theme mode (light/dark/system)
const useThemedStyles = createThemedStyles((theme) => ({
container: {
flex: 1,
backgroundColor: theme.colors.background,
padding: theme.spacing.md,
},
text: {
color: theme.colors.text,
},
}));
// ๐งฑ Styles that use theme tokens but remain static across theme modes
const staticStyles = createStaticStyles((theme) => ({
text: {
fontSize: 18,
fontWeight: 'bold',
color: theme.colors.light.primary, // fixed value from light mode
},
}));
const MyComponent = () => {
const styles = useThemedStyles();
return (
<View style={styles.container}>
<Text style={styles.text}>
I react to theme mode changes
</Text>
<Text style={staticStyles.text}>
I stay the same across all modes
</Text>
</View>
);
};- Toggle theme mode
import { useToggleThemeMode } from '@theme';
const ToggleButton = () => {
const toggleTheme = useToggleThemeMode();
return <Button title="Toggle Theme" onPress={toggleTheme} />;
};๐ง Other Utilities
Once you initialize your theme system with createAppTheme(), you get access to the following utilities:
| Utility | Description |
|---|---|
useTheme() |
Access the current theme (colors, colorMode, and custom tokens). |
useThemeMode() |
Get the current theme mode (light, dark, or system). |
useSetThemeMode() |
Change the theme mode programmatically. |
useResetThemeMode() |
Reset to system theme mode (and clear stored preference if storage: true). |
useToggleThemeMode() |
Toggle strictly between light and dark modes. |
useCycleThemeMode() |
Cycle through modes: light โ dark โ system โ light. |
createThemedStyles() |
Create memoized themed styles using your theme object. |
createStaticStyles() |
Create static styles using your theme object.(non-reactive) |
useResolveColor() |
NEW: Resolves a dynamic color object or string to the correct value for the current theme. Useful for external libraries or APIs (like Reanimated) that do not support iOS dynamic colors. |
All of these must be used within your AppThemeProvider tree.
๐งฉ Best Practices
โ
Use useTheme() for direct access to the theme
โ
Use createThemedStyles() for most of your app โ these styles respond to light/dark mode and adapt dynamically.
โ
Use createStaticStyles() only when you need styles that remain fixed across all theme modes but still leverage theme tokens.
๐ก Define createThemedStyles() and createStaticStyles() outside of components for maximum efficiency & performance
๐ซ Do not call createAppTheme() more than once per app
๐ License
MIT ยฉ KJ-GM


