Implementing Dark Mode in React with Context API – Step-by-Step Guide


Implementing Dark Mode in React with Context API – Step-by-Step Guide

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 using createContext().
  • useState stores the current theme.
  • useEffect ensures the theme is saved to and read from localStorage.
  • 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.


Leave a Comment

Your email address will not be published. Required fields are marked *