How to add dark mode and a theme toggle in React Native
By the LumioUI team · Updated
To add dark mode in React Native, read the system setting with useColorScheme(), keep an optional user override in a theme context, and take every colour from theme tokens instead of hard-coding them. A toggle then just sets the override. LumioUI's ThemeProvider and Theme Toggle give you all of this, with a sun that turns into a crescent moon.
Live demo of the LumioUI Theme Toggle component. It's interactive, so try it.
How dark mode works in React Native
- Follow the system first.
useColorScheme()returns"light"or"dark"and updates when the phone switches, for example at sunset. Most people never touch your toggle, so this default matters most. - Let people override it. Store
"system" | "light" | "dark"in context, and persist it (AsyncStorage or MMKV) so it survives restarts. - Use semantic tokens. Screens ask for
backgroundandtext, not#fff. With NativeWind that'sbg-backgroundandtext-foreground. One theme change then recolours everything. - Status bar and splash. Flip the status-bar style with the scheme, and set
userInterfaceStyle: "automatic"in your Expo config.
import * as React from "react";
import { useColorScheme } from "react-native";
type Scheme = "light" | "dark";
const ThemeCtx = React.createContext<{ scheme: Scheme; setOverride: (s: Scheme | "system") => void }>(null!);
export function ThemeProvider({ children }: { children: React.ReactNode }) {
const system = useColorScheme() ?? "light"; // follows the phone
const [override, setOverride] = React.useState<Scheme | "system">("system");
const scheme = override === "system" ? system : override;
return <ThemeCtx.Provider value={{ scheme, setOverride }}>{children}</ThemeCtx.Provider>;
}
export const useTheme = () => React.useContext(ThemeCtx);
// Colours come from tokens, never hard-coded per screen:
export const colors = {
light: { background: "#fafafa", text: "#0b0b0b" },
dark: { background: "#0f0f0f", text: "#f2f2f2" },
}; The quick way: LumioUI theme + Theme Toggle
npx @lumioui/cli init installs the theme (tokens, ThemeProvider, the NativeWind setup) into lib/lumioui. Wrap your app once:
// app/_layout.tsx (Expo Router) or App.tsx
import "./global.css";
import { ThemeProvider } from "@/lib/lumioui";
export default function RootLayout() {
return <ThemeProvider>{/* your app */}</ThemeProvider>;
} Drop in the toggle wherever people expect it:
import { ThemeToggle } from "@/components/ui/theme-toggle/theme-toggle";
// In a header or settings row. Without a scheme prop it reads and sets
// the app theme for you; variant: "icon" | "pill" | "switch".
<ThemeToggle variant="icon" /> Style screens with semantic classes, and they follow the theme with no extra code:
<View className="bg-background">
<Text className="text-foreground">Follows light and dark automatically</Text>
<Text className="text-muted-foreground">So does this</Text>
</View> useTheme()exposesscheme,colors(for things classes can't reach, like SVG strokes) andsetSchemeOverride("system" | "light" | "dark").- Pass
schemeandonSchemeChangetoThemeToggleto control it yourself. The callback also tells you where the tap happened. - Use that tap position with Circle Reveal to flood the new theme out from the button.
Theming goes further, with accents, custom tokens and fixed-scheme sections. See the theming docs.
Add it to your app
LumioUI's CLI copies the component's source into your project, so it's yours to read and change. Run init once per project:
npx @lumioui/cli init
npx @lumioui/cli add theme-toggle It works in Expo (SDK 54+) and bare React Native, with Reanimated 4 and NativeWind. See the installation guide and the full Theme Toggle API.
Related components
More React Native guides
- How to make a bottom sheet in React Native
- Animated tabs with a sliding indicator in React Native
- How to show toast notifications in React Native
- Skeleton loading screens in React Native
- How to build an accordion in React Native
- How to make a side drawer menu in React Native
- How to make an animated heart like button in React Native
- How to make a modal dialog in React Native
- How to build an animated carousel in React Native
- How to make an animated splash screen in React Native and Expo
- How to build a month calendar in React Native