
Dark mode has become a standard feature in modern applications. Beyond aesthetics, it offers real usability benefits—especially for users browsing at night or on OLED displays. As React applications scale, implementing global state management for such features becomes critical.
In this guide, you’ll learn how to implement dark mode in React using the Context API, allowing theme state to be shared seamlessly across your application without relying on external libraries.
Why Use Context API for Dark Mode?
React’s Context API allows you to manage global state efficiently—especially for values like the UI theme, authentication status, language settings, and more.
Here’s why Context API is suitable for implementing dark mode:
- Avoids prop drilling: No need to pass the theme state manually through multiple component layers.
- Centralized control: Manage and toggle the theme from a single source.
- Lightweight and built-in: No need for third-party state libraries like Redux for simple global state.
Step 1: Set Up a New React Project
If you don’t have a React app set up yet, use Create React App:
npx create-react-app dark-mode-demo
cd dark-mode-demo
npm start
This will spin up a development environment with hot reloading.
Step 2: Create a Theme Context
Inside the src
directory, create a new file called ThemeContext.js
to define your global theme context.
import React, { createContext, useState, useEffect } from 'react';
export const ThemeContext = createContext();
export function ThemeProvider({ children }) {
const [isDarkMode, setIsDarkMode] = useState(() => {
// Load saved theme preference from localStorage
const savedTheme = localStorage.getItem('darkMode');
return savedTheme === 'true' || false;
});
useEffect(() => {
// Save user preference when toggled
localStorage.setItem('darkMode', isDarkMode);
}, [isDarkMode]);
const toggleTheme = () => setIsDarkMode(prev => !prev);
const contextValue = {
isDarkMode,
toggleTheme,
};
return (
<ThemeContext.Provider value={contextValue}>
{children}
</ThemeContext.Provider>
);
}
Explanation:
ThemeContext
is created usingcreateContext()
.useState
stores the current theme.useEffect
ensures the theme is saved to and read fromlocalStorage
.ThemeProvider
wraps your app and supplies the state to all consuming components.
Step 3: Wrap the App with ThemeProvider
To apply the context across the app, wrap the root component with ThemeProvider
.
Update index.js
:
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { ThemeProvider } from './ThemeContext';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<ThemeProvider>
<App />
</ThemeProvider>
);
This ensures that any component inside App
can access the theme context.
Step 4: Consume the Theme Context in Your Component
Update App.js
to use the useContext
Hook and respond to theme state.
import React, { useContext } from 'react';
import { ThemeContext } from './ThemeContext';
import './App.css';
function App() {
const { isDarkMode, toggleTheme } = useContext(ThemeContext);
return (
<div className={isDarkMode ? 'app dark' : 'app'}>
<h1>{isDarkMode ? 'Dark Mode Enabled' : 'Light Mode Enabled'}</h1>
<button onClick={toggleTheme}>
Switch to {isDarkMode ? 'Light' : 'Dark'} Mode
</button>
</div>
);
}
export default App;
Key Concepts:
useContext(ThemeContext)
gives access to the current theme and toggle function.- The root
div
has a conditional class for styling. - The button updates the theme state when clicked.
Step 5: Add Theme-Based Styling
Edit App.css
to define both light and dark themes:
.app {
background-color: #ffffff;
color: #111111;
min-height: 100vh;
padding: 2rem;
transition: background-color 0.3s ease, color 0.3s ease;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.app.dark {
background-color: #121212;
color: #f5f5f5;
}
button {
margin-top: 20px;
padding: 12px 24px;
font-size: 1rem;
background-color: transparent;
border: 2px solid currentColor;
border-radius: 5px;
cursor: pointer;
}
You can enhance the UI with animations or CSS variables for a smoother transition.
Step 6: Advanced: Using prefers-color-scheme
for System Theme Detection
Modern browsers support detecting the user’s system theme using the window.matchMedia
API.
Enhance your ThemeProvider
:
const getInitialTheme = () => {
const saved = localStorage.getItem('darkMode');
if (saved !== null) return saved === 'true';
const systemPrefersDark = window.matchMedia &&
window.matchMedia('(prefers-color-scheme: dark)').matches;
return systemPrefersDark;
};
export function ThemeProvider({ children }) {
const [isDarkMode, setIsDarkMode] = useState(getInitialTheme);
useEffect(() => {
localStorage.setItem('darkMode', isDarkMode);
}, [isDarkMode]);
const toggleTheme = () => setIsDarkMode(prev => !prev);
return (
<ThemeContext.Provider value={{ isDarkMode, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
}
Now your app will use the system default theme if no preference has been set yet.
Additional Improvements (Optional)
You can further improve your dark mode implementation by:
- Using CSS variables for dynamic theming
- Applying themes to third-party libraries (e.g., charts, modals)
- Supporting theme switcher icons (like sun/moon toggles)
- Adding persistent settings in a user profile or database
- Implementing transition effects when switching themes
Final Thoughts
Dark mode isn’t just a trend—it’s an expectation in modern user experiences. With React’s Context API, implementing and managing dark mode is both simple and scalable. You can:
- Avoid unnecessary re-renders or prop drilling
- Easily maintain global UI settings
- Build a cleaner architecture for theming
Whether you’re building a portfolio, dashboard, or SaaS product, a theme toggle adds polish and improves accessibility. Start small, but design with user comfort in mind—and React Context gives you all the tools to do it right.

I’m Shreyash Mhashilkar, an IT professional who loves building user-friendly, scalable digital solutions. Outside of coding, I enjoy researching new places, learning about different cultures, and exploring how technology shapes the way we live and travel. I share my experiences and discoveries to help others explore new places, cultures, and ideas with curiosity and enthusiasm.