Bring Material 3 Dynamic Theming to Your React Native Apps
A powerful React Native library that enables seamless Material 3 dynamic theming, automatically adapting to your users' system preferences and wallpaper colors on Android 12+.
- π± System-Aware: Automatically adapts to light/dark mode
- π¨ Material You Support: Leverages Android's dynamic theming for native feel
- π― Complete Color Palettes: Access to full tonal palettes with all contrast levels
- β‘ Performance Optimized: Efficient hooks and memoization
- π§ Custom Color Generation: Create themes from any source color
- π¦ TypeScript Support: Fully typed for better development experience
- π Extended Schemes: Medium and high contrast variants included
npm install react-native-dynamic-theme
or
yarn add react-native-dynamic-theme
import React from 'react';
import { View, Text, useColorScheme } from 'react-native';
import { getDynamicColorScheme } from 'react-native-dynamic-theme';
const App = () => {
const systemColorScheme = useColorScheme();
const dynamicColors = getDynamicColorScheme('#006971');
const colors = systemColorScheme === 'dark'
? dynamicColors.dark
: dynamicColors.light;
return (
<View style={{ backgroundColor: colors.background, flex: 1 }}>
<Text style={{ color: colors.onBackground }}>
Hello Material You! π¨
</Text>
</View>
);
};
export default App;
Retrieves the dynamic color scheme from the device or generates one from a fallback color.
// Uses device wallpaper colors on Android 12+, fallback on older versions
const colors = getDynamicColorScheme('#006971');
// Returns null if no fallback provided and device doesn't support dynamic theming
const colors = getDynamicColorScheme();
Gets extended scheme with contrast variants and tonal palettes.
const extendedScheme = getExtendedDynamicScheme('#006971');
// Access different contrast levels
const standardColors = extendedScheme.schemes.light;
const highContrastColors = extendedScheme.schemes.lightHighContrast;
// Access tonal palettes
const primaryPalette = extendedScheme.palettes.primary;
Generate complete theme from any source color.
const customScheme = getExtendedDynamicSchemeFromSourceColor('#FF5722');
import React, { useState } from 'react';
import { View, TouchableOpacity, Text, useColorScheme } from 'react-native';
import { getExtendedDynamicSchemeFromSourceColor } from 'react-native-dynamic-theme';
const ThemeSwitcher = () => {
const systemColorScheme = useColorScheme();
const [sourceColor, setSourceColor] = useState('#006971');
const colorOptions = ['#006971', '#FF5722', '#2196F3', '#9C27B0'];
const dynamicScheme = getExtendedDynamicSchemeFromSourceColor(sourceColor);
const colors = systemColorScheme === 'dark'
? dynamicScheme.dark
: dynamicScheme.light;
return (
<View style={{ backgroundColor: colors.background, flex: 1, padding: 20 }}>
<Text style={{ color: colors.onBackground, fontSize: 24, marginBottom: 20 }}>
Pick a Color Theme
</Text>
<View style={{ flexDirection: 'row', marginBottom: 20 }}>
{colorOptions.map((color) => (
<TouchableOpacity
key={color}
style={{
backgroundColor: color,
width: 50,
height: 50,
borderRadius: 25,
marginRight: 10,
borderWidth: sourceColor === color ? 3 : 0,
borderColor: colors.outline,
}}
onPress={() => setSourceColor(color)}
/>
))}
</View>
<View style={{
backgroundColor: colors.primaryContainer,
padding: 16,
borderRadius: 12,
}}>
<Text style={{ color: colors.onPrimaryContainer }}>
This container adapts to your selected color!
</Text>
</View>
</View>
);
};
- React Native: 0.60+
- Android: API 21+ (dynamic colors on API 31+)
- iOS: 11.0+ (custom color generation)
- TypeScript: 4.0+
- Android 12+: Uses actual device wallpaper colors via Material You
- Android < 12: Generates theme from fallback color
- iOS: Generates theme from fallback color (Material You not available)
The library provides access to the complete Material 3 color system:
- Primary, Secondary, Tertiary colors and their containers
- Error colors and containers
- Background and surface colors
- Surface containers at different elevation levels
- Outline colors for borders and dividers
const { colors } = useTheme();
// Main actions
backgroundColor: colors.primary
color: colors.onPrimary
// Supporting actions
backgroundColor: colors.secondaryContainer
color: colors.onSecondaryContainer
// Error states
backgroundColor: colors.errorContainer
color: colors.onErrorContainer
// Surfaces
backgroundColor: colors.surface
color: colors.onSurface
import React, { createContext, useContext } from 'react';
import { useColorScheme } from 'react-native';
import { getDynamicColorScheme } from 'react-native-dynamic-theme';
const ThemeContext = createContext();
export const ThemeProvider = ({ children }) => {
const systemColorScheme = useColorScheme();
const dynamicColors = getDynamicColorScheme('#006971');
const colors = systemColorScheme === 'dark'
? dynamicColors.dark
: dynamicColors.light;
return (
<ThemeContext.Provider value={{ colors, isDark: systemColorScheme === 'dark' }}>
{children}
</ThemeContext.Provider>
);
};
export const useTheme = () => useContext(ThemeContext);
import { useMemo } from 'react';
const MyComponent = ({ sourceColor }) => {
// Memoize expensive color calculations
const colors = useMemo(() => {
return getDynamicColorScheme(sourceColor);
}, [sourceColor]);
return <View style={{ backgroundColor: colors.light.background }} />;
};
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/AmazingFeature
) - Commit your changes (
git commit -m 'Add some AmazingFeature'
) - Push to the branch (
git push origin feature/AmazingFeature
) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
- Built with Material Color Utilities
- Inspired by Android's Material You design system
- Thanks to the React Native community
- Documentation: https://react-native-dynamic-theme.vercel.app
- Issues: GitHub Issues
- Discussions: GitHub Discussions
Made with β€οΈ by Fouad Magdy