Dark Mode Made Easy with Chakra UI’s ColorModeProvider
Chakra UI’s ColorModeProvider gives React apps a declarative, context‑driven dark‑mode solution. Learn how to toggle themes, customize palettes, and handle persistence with localStorage or a custom storage engine.
30 Mar 2026, 10:01 UTC

Problem: Managing Dark Mode in a React App
Modern UI libraries expose a light/dark toggle, but many developers still build custom solutions that are error‑prone and hard to maintain. The core issue is that themes often live in CSS files or as hard‑coded style objects, making persistence and component consistency difficult.
Thesis: Chakra UI’s ColorModeProvider solves this by providing a declarative, context‑driven API that automatically injects CSS variables and persists the choice.
Core Concepts
ColorModeProvider & useColorMode Hook
The ColorModeProvider wraps your app and supplies a React context containing colorMode ("light" or "dark") and a toggleColorMode function. The useColorMode hook lets any component read or change the mode.
Automatic CSS Variable Injection
When the provider mounts, Chakra injects a set of --chakra-colors-… variables into :root. Components reference these variables, so switching the mode updates all styles in a single CSS cascade.
Persistence Layer
By default the provider stores the current mode in localStorage under the key chakra-ui-color-mode. The storageManager prop allows swapping this for a cookie, session storage, or a custom API—essential for SSR or privacy‑conscious apps.
Using the Default Theme
// index.js
import { ChakraProvider, ColorModeProvider } from "@chakra-ui/react";
import App from "./App";
ReactDOM.createRoot(document.getElementById("root")).render(
<ChakraProvider>
<ColorModeProvider>
<App />
</ColorModeProvider>
</ChakraProvider>
);
Now any component can toggle the mode:
import { Button, useColorMode } from "@chakra-ui/react";
function ThemeToggle() {
const { colorMode, toggleColorMode } = useColorMode();
return (
<Button onClick={toggleColorMode}>
Switch to {colorMode === "light" ? "dark" : "light"}
</Button>
);
}
Customizing Dark Mode Palettes
Teams often need branded colors. Override the theme’s palette and colorModeKey to keep Chakra’s API intact:
import { extendTheme, ChakraProvider, ColorModeProvider } from "@chakra-ui/react";
const customTheme = extendTheme({
config: {
initialColorMode: "light",
useSystemColorMode: false,
},
colors: {
brand: {
50: "#e3f2f9",
500: "#0d47a1",
900: "#001a4d",
},
},
styles: {
global: {
":root": {
"--chakra-colors-brand-500": "#0d47a1",
"--chakra-colors-brand-900": "#001a4d",
},
},
},
});
ReactDOM.createRoot(document.getElementById("root")).render(
<ChakraProvider theme={customTheme}>
<ColorModeProvider>
<App />
</ColorModeProvider>
</ChakraProvider>
);
Components using brand.500 will now respect the custom palette in both light and dark modes.
Trade‑off: Privacy vs Convenience
Storing the mode in localStorage is simple but exposes the preference to any script running on the page. If your app handles sensitive data, consider:
- Using a cookie with the
SameSiteflag and noHttpOnlyto keep the value client‑side but limit cross‑origin leakage. - Implementing a server‑side storage manager that reads a cookie on the initial request and writes back on toggle via an API endpoint.
Each option adds complexity but improves privacy. Evaluate based on your compliance requirements.
Actionable Next Steps
- Wrap your app with
ColorModeProviderand test the toggle button. - Verify persistence by reloading the page and checking
localStorage["chakra-ui-color-mode"]. - Inspect
:rootin dev tools to see the--chakra-colors-…variables change when you switch modes. - If you need custom branding, extend the theme as shown and rebuild your components to use the new palette keys.
- For SSR or privacy, implement a
storageManagerthat reads/writes from a cookie or server endpoint.
By following these steps, you’ll have a robust, declarative dark‑mode system that scales with your project and respects user preferences.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.