βοΈ Introduction
Dark mode has become a must-have feature in modern web apps π.
Itβs not just about style β it improves accessibility, reduces eye strain, and adds a sleek aesthetic to your app β¨.
In this article, weβll build a Dark Mode Toggle feature in React using the Context API, so that theme changes are shared across your entire app β easily and efficiently! β‘
π§ Why Use Context API for Dark Mode?
Normally, you can manage theme toggles with useState, but if you have multiple components that need to know the theme (like Navbar, Footer, Cards, etc.), passing props everywhere becomes messy. π©
Thatβs where Reactβs Context API comes in!
It lets you:
ποΈ Step 1. Set up a React App
If you donβt already have a React app, create one:
npx create-react-app dark-mode-toggle
cd dark-mode-toggle
npm start
Now, youβre ready to build the dark mode feature! π
βοΈ Step 2. Create a Theme Context
Inside your src folder, create a new file:
π ThemeContext.js
import { createContext, useState, useContext } from "react";
// Step 1: Create the context
const ThemeContext = createContext();
// Step 2: Create a provider component
export function ThemeProvider({ children }) {
const [theme, setTheme] = useState("light");
const toggleTheme = () => {
setTheme((prevTheme) => (prevTheme === "light" ? "dark" : "light"));
};
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
}
// Step 3: Custom hook to use the Theme Context easily
export function useTheme() {
return useContext(ThemeContext);
}
β
Explanation
ThemeContext holds our theme state (light or dark)
ThemeProvider wraps our entire app and provides theme info
toggleTheme switches between light and dark modes
useTheme() is a helper hook for easy access
π Step 3. Wrap Your App with ThemeProvider
Now open index.js (or main.jsx if using Vite) and wrap your app inside the ThemeProvider.
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import { ThemeProvider } from "./ThemeContext";
import "./index.css";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<ThemeProvider>
<App />
</ThemeProvider>
);
π― This ensures that every component in your app can access the theme context.
π‘ Step 4. Create a Toggle Button Component
Now letβs create a button to switch between dark and light themes.
π ThemeToggle.js
import React from "react";
import { useTheme } from "./ThemeContext";
function ThemeToggle() {
const { theme, toggleTheme } = useTheme();
return (
<button
onClick={toggleTheme}
style={{
padding: "10px 20px",
borderRadius: "10px",
border: "none",
cursor: "pointer",
backgroundColor: theme === "light" ? "#333" : "#fff",
color: theme === "light" ? "#fff" : "#333",
transition: "all 0.3s ease",
}}
>
{theme === "light" ? "π Dark Mode" : "βοΈ Light Mode"}
</button>
);
}
export default ThemeToggle;
π§ Explanation
We use the useTheme() hook to access the theme and toggleTheme
Button style changes dynamically based on the current theme
Emoji icons πβοΈ make it fun and intuitive
π₯οΈ Step 5. Apply the Theme to the App
Letβs make our app background and text color change with the theme.
App.js π
import React from "react";
import { useTheme } from "./ThemeContext";
import ThemeToggle from "./ThemeToggle";
function App() {
const { theme } = useTheme();
const appStyles = {
backgroundColor: theme === "light" ? "#f9f9f9" : "#121212",
color: theme === "light" ? "#000" : "#fff",
minHeight: "100vh",
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
transition: "all 0.3s ease-in-out",
};
return (
<div style={appStyles}>
<h1>React Dark Mode with Context API πβοΈ</h1>
<p>Switch between themes easily using Context!</p>
<ThemeToggle />
</div>
);
}
export default App;
π§ Step 6: How It Works
When you click the toggle button:
toggleTheme() updates the state inside ThemeProvider.
The new theme value (light or dark) is passed through Context.
ll components using useTheme() automatically re-render and apply the new styles.
π Boom! Your entire app now switches themes smoothly.
π Step 7 (Optional): Persist Theme in Local Storage
To remember the userβs theme preference after page reloads, you can save it in localStorage.
Modify ThemeProvider like this π
import { createContext, useState, useEffect, useContext } from "react";
const ThemeContext = createContext();
export function ThemeProvider({ children }) {
const [theme, setTheme] = useState(() => {
return localStorage.getItem("theme") || "light";
});
useEffect(() => {
localStorage.setItem("theme", theme);
}, [theme]);
const toggleTheme = () => {
setTheme((prev) => (prev === "light" ? "dark" : "light"));
};
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
}
export function useTheme() {
return useContext(ThemeContext);
}
β
Now the theme stays even after page refresh π
π§© Step 8. (Bonus) Add CSS Transitions or Tailwind Support
If youβre using Tailwind CSS, you can easily integrate dark mode by toggling the dark class on the <html> element.
Example
useEffect(() => {
document.documentElement.classList.toggle("dark", theme === "dark");
}, [theme]);
Then, in Tailwind config, enable dark mode:
module.exports = {
darkMode: "class",
// ...
};
Now, your entire UI will follow the theme dynamically β¨
π« Benefits of Using Context API for Dark Mode
Feature: Why It Helps
π Global Access All components share the same theme
π§ Clean Code No prop drilling
β‘ Performance React only re-renders components that use context
πΎ Persistent Easily save user preferences
π¨ Flexible Works with CSS, Tailwind, or Styled Components
π Final Output
π Light Mode
π€ Dark Mode
Switch smoothly with one click, and your app remembers the choice!
π§ Conclusion
With just a few lines of code, you built a fully functional Dark Mode toggle using Reactβs Context API. π
You learned how to:
Use Context API for global theme state π
Toggle between light and dark themes dynamically π
Persist theme preferences with localStorage πΎ
This pattern is reusable for any global state β not just themes, but also language, authentication, or user preferences. β‘
So next time someone asks how to implement dark mode β
youβll say, βEasy β React + Context API!β πβοΈ