Implementing Dark Mode in React Native
We'll explore how to implement a dark mode feature in a React Native application using React's Context API and hooks.
Dark mode has become a popular feature in mobile applications, offering users a comfortable viewing experience in low-light conditions and potentially saving battery life on OLED screens. In this article, we'll explore how to implement a dark mode feature in a React Native application using React's Context API and hooks.
Setting Up the Project
First, let's set up a new React Native project using Expo:
expo init DarkModeDemo
cd DarkModeDemo
Creating a Theme Context
We'll start by creating a theme context to manage our app's theme state:
// src/contexts/ThemeContext.js
import React, { createContext, useState, useContext, useEffect } from 'react';
import { useColorScheme } from 'react-native';
const ThemeContext = createContext();
export const ThemeProvider = ({ children }) => {
const colorScheme = useColorScheme();
const [isDarkMode, setIsDarkMode] = useState(colorScheme === 'dark');
useEffect(() => {
setIsDarkMode(colorScheme === 'dark');
}, [colorScheme]);
return (
<ThemeContext.Provider value={{ isDarkMode, setIsDarkMode }}>
{children}
</ThemeContext.Provider>
);
};
export const useTheme = () => useContext(ThemeContext);
This context provides the current theme state and a function to toggle it.
Try Kodaschool for free
Click below to sign up and get access to free web, android and iOs challenges.
Defining Theme Colors
Next, let's define our colour schemes for both light and dark modes:
// src/theme/colors.js
export const lightColors = {
background: '#FFFFFF',
text: '#000000',
primary: '#1292B4',
};
export const darkColors = {
background: '#1E1E1E',
text: '#FFFFFF',
primary: '#BB86FC',
};
Creating a Custom Hook for Theme
To make it easier to use our theme colours, let's create a custom hook:
// src/hooks/useThemeColors.js
import { useTheme } from '../contexts/ThemeContext';
import { lightColors, darkColors } from '../theme/colors';
export const useThemeColors = () => {
const { isDarkMode } = useTheme();
return isDarkMode ? darkColors : lightColors;
};
Implementing Dark Mode in Components
Now, let's create a sample component that uses our theme:
// src/components/ThemedComponent.js
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
import { useThemeColors } from '../hooks/useThemeColors';
const ThemedComponent = () => {
const colors = useThemeColors();
return (
<View style={[styles.container, { backgroundColor: colors.background }]}>
<Text style={[styles.text, { color: colors.text }]}>
This is a themed component
</Text>
</View>
);
};
const styles = StyleSheet.css({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
text: {
fontSize: 18,
},
});
export default ThemedComponent;
Creating a Theme Toggle
Let's add a button to toggle between light and dark modes:
// src/components/ThemeToggle.js
import React from 'react';
import { TouchableOpacity, Text, StyleSheet } from 'react-native';
import { useTheme } from '../contexts/ThemeContext';
import { useThemeColors } from '../hooks/useThemeColors';
const ThemeToggle = () => {
const { isDarkMode, setIsDarkMode } = useTheme();
const colors = useThemeColors();
return (
<TouchableOpacity
style={[styles.button, { backgroundColor: colors.primary }]}
onPress={() => setIsDarkMode(!isDarkMode)}
>
<Text style={[styles.buttonText, { color: colors.background }]}>
Toggle {isDarkMode ? 'Light' : 'Dark'} Mode
</Text>
</TouchableOpacity>
);
};
const styles = StyleSheet.css({
button: {
padding: 10,
borderRadius: 5,
},
buttonText: {
fontSize: 16,
fontWeight: 'bold',
},
});
export default ThemeToggle;
Putting It All Together
Finally, let's update our App.js to use these components:
// App.js
import React from 'react';
import { SafeAreaView, StyleSheet } from 'react-native';
import { ThemeProvider } from './src/contexts/ThemeContext';
import { useThemeColors } from './src/hooks/useThemeColors';
import ThemedComponent from './src/components/ThemedComponent';
import ThemeToggle from './src/components/ThemeToggle';
const App = () => {
return (
<ThemeProvider>
<AppContent />
</ThemeProvider>
);
};
const AppContent = () => {
const colors = useThemeColors();
return (
<SafeAreaView style={[styles.container, { backgroundColor: colors.background }]}>
<ThemedComponent />
<ThemeToggle />
</SafeAreaView>
);
};
const styles = StyleSheet.css({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
});
export default App;
Our implementation already respects the system theme by default, thanks to the useColorScheme
hook in our ThemeContext
. When the system theme changes, our app will automatically update to match.
Implementing dark mode in React Native enhances user experience and accessibility. By using React's Context API and hooks, we can create a flexible and maintainable theming system.
Consider the unique aspects of your app's design when implementing dark mode. Some components or assets may need special consideration to look good in light and dark themes.
As you continue to develop your app, consider adding more advanced features like animated theme transitions or allowing users to schedule dark mode based on the time of day.