Light & Dark Mode in React Native with Design Tokens
By Arslan Shaukat
Hardcoded hex values and padding: 16 scattered across files are how an app slowly drifts out of consistency — and why adding dark mode later feels impossible. The fix is to drive everything from design tokens: one source of truth for color, spacing, and radius. Here's how.
Define the tokens
Start with two palettes and a few scales:
export const light = {
bg: "#F6F6FB",
surface: "#FFFFFF",
text: "#15151F",
accent: "#5B57E6",
};
export const dark = {
bg: "#0A0A14",
surface: "#12121F",
text: "#ECECF5",
accent: "#7C7AF5",
};
export const space = (n: number) => n * 8;
export const radius = { md: 12, lg: 18 };Every color in the app comes from one of these objects. There are no raw hex values in components, ever.
Expose the active theme
Put the current palette behind a context so components read tokens, not values:
const ThemeCtx = createContext(dark);
export const useTheme = () => useContext(ThemeCtx);
export function ThemeProvider({ children }: { children: ReactNode }) {
const scheme = useColorScheme(); // "light" | "dark"
const value = scheme === "light" ? light : dark;
return <ThemeCtx.Provider value={value}>{children}</ThemeCtx.Provider>;
}useColorScheme from React Native follows the device setting automatically, so the app respects the user's OS preference out of the box.
Use tokens in components
function Card({ children }: { children: ReactNode }) {
const t = useTheme();
return (
<View style={{ backgroundColor: t.surface, borderRadius: radius.lg, padding: space(2) }}>
{children}
</View>
);
}Because the component reads t.surface rather than a literal color, it's correct in both themes with zero extra code.
Why this scales
- A redesign is a token change, not a find-and-replace across fifty files.
- Dark mode is free — it's just the second palette.
- Consistency is enforced because there's nowhere to put a one-off color.
This is the "no magic numbers" rule, and it's baked into both my React Native Starter and the AI Chat App UI Kit — every color and spacing value flows from tokens, so theming is a solved problem from the first screen.
Skip the boilerplate
Production-ready React Native starters and UI kits — buy once, clone, and start on the feature that matters.
Browse the templatesMore