Dark Mode
How to add dark mode support to your app using NativeWind and ThemeProvider.
- 1
Add async-storage
First, add the async-storage to your project using the following command:
npx expo install @react-native-async-storage/async-storage
First, add the async-storage to your project using the following command:
- 2
Create ThemeProvider
Then create a ThemeProvider component:
import { PropsWithChildren, useEffect, useMemo, useState } from "react"; import { useColorScheme } from "nativewind"; import { DarkTheme, DefaultTheme, ThemeProvider as RNThemeProvider, } from "@react-navigation/native"; import { useColorScheme as RNUseColorScheme } from "react-native"; import AsyncStorage from "@react-native-async-storage/async-storage"; DefaultTheme.colors.background = "white"; DarkTheme.colors.background = "#09090B"; export const ThemeProvider = ({ children }: PropsWithChildren) => { const [loaded, setLoaded] = useState(false); const { colorScheme, setColorScheme } = useColorScheme(); const rnColorScheme = RNUseColorScheme(); useEffect(() => { if (loaded) { (async () => { const theme = await AsyncStorage.getItem("theme"); if (!theme) { const cs = rnColorScheme === "dark" ? "dark" : "light"; await AsyncStorage.setItem("theme", cs); setColorScheme(cs); return; } if (colorScheme && theme !== colorScheme) { await AsyncStorage.setItem("theme", colorScheme); return; } })(); } }, [colorScheme, loaded]); useEffect(() => { (async () => { const theme = await AsyncStorage.getItem("theme"); if (theme) { setColorScheme(theme as "light" | "dark"); } setLoaded(true); })(); }, []); const isDarkMode = useMemo( () => (!loaded && rnColorScheme === "dark") || colorScheme === "dark", [loaded, rnColorScheme, colorScheme] ); return ( <RNThemeProvider value={isDarkMode ? DarkTheme : DefaultTheme}> {children} </RNThemeProvider> ); };
- 3
Wrap your app with ThemeProvider
In your root layout file, wrap your app component with the ThemeProvider:
import { ThemeProvider } from "@/providers/ThemeProvider" export default function RootLayout({ children }) { return ( <ThemeProvider> {children} </ThemeProvider> ) }
- 4
Use the useColorScheme hook
You can now use NativeWind's useColorScheme hook to manage the color scheme:
import React, { useEffect } from 'react'; import { useColorScheme } from "nativewind"; import { Button } from "@/components/Button" import { Text } from "@/components/Text" function ThemeToggle() { const { colorScheme, setColorScheme } = useColorScheme(); useEffect(() => { setColorScheme('dark'); }, []); const toggleColorScheme = () => { setColorScheme(colorScheme === 'dark' ? 'light' : 'dark'); }; return ( <Button onPress={toggleColorScheme}> <Text>Toggle theme (Current: {colorScheme})</Text> </Button> ); }
Note
The ThemeProvider ensures that the color scheme is properly managed throughout your app. NativeWind's useColorScheme hook allows you to programmatically control the color scheme, integrating seamlessly with React Native's appearance API.