DEV Community

Cover image for Building a Dark Mode Toggle in React with Context API
Vrushik Visavadiya
Vrushik Visavadiya

Posted on

Building a Dark Mode Toggle in React with Context API

Dark mode is a must-have feature in modern web apps. It enhances user experience and can reduce eye strain. In this post, we'll walk through how to implement a Dark Mode Toggle in a React app using the Context API to manage state globally.

We'll create a simple app where users can toggle between dark and light modes, with their preference stored in localStorage so it persists even after they leave or reload the page.

Step 1: Set up the Context

The first step is to create a ThemeContext that will provide the dark mode state and the toggle function to any component in the app.

// src/context/ThemeContext.js
import React, { createContext, useState, useEffect } from 'react';

export const ThemeContext = createContext();

export const ThemeProvider = ({ children }) => {
  const [darkMode, setDarkMode] = useState(() => {
    const savedMode = localStorage.getItem('dark-mode');
    return savedMode === 'true' || false;
  });

  useEffect(() => {
    localStorage.setItem('dark-mode', darkMode);
    document.body.className = darkMode ? 'dark-mode' : '';
  }, [darkMode]);

  const toggleDarkMode = () => {
    setDarkMode((prevMode) => !prevMode);
  };

  return (
    <ThemeContext.Provider value={{ darkMode, toggleDarkMode }}>
      {children}
    </ThemeContext.Provider>
  );
};

Enter fullscreen mode Exit fullscreen mode

Here, we're using useState to initialize the theme based on localStorage. useEffect ensures that whenever the theme changes, it updates localStorageand applies the appropriate class to the body element.


Step 2: Create the Toggle Component

Here, we use useContext to consume the darkModevalue and toggleDarkMode function from the ThemeContext.

// src/components/ThemeToggle.js
import React, { useContext } from 'react';
import { ThemeContext } from '../context/ThemeContext';

const ThemeToggle = () => {
  const { darkMode, toggleDarkMode } = useContext(ThemeContext);

  return (
    <button onClick={toggleDarkMode}>
      {darkMode ? 'Switch to Light Mode' : 'Switch to Dark Mode'}
    </button>
  );
};

export default ThemeToggle;


Enter fullscreen mode Exit fullscreen mode

Step 3: Apply Dark Mode Styles

To see the dark mode in action, you'll need to add some CSS styles. For simplicity, we'll apply a dark theme to the bodyelement.

/* src/styles.css */
body {
  margin: 0;
  font-family: sans-serif;
  transition: background-color 0.3s ease;
}

body.dark-mode {
  background-color: #121212;
  color: white;
}


Enter fullscreen mode Exit fullscreen mode

Step 4: Set up the App Component

Here, we wrap the entire app inside the ThemeProvider, which allows the dark mode state and toggle function to be available globally.

// src/App.js
import React from 'react';
import { ThemeProvider } from './context/ThemeContext';
import ThemeToggle from './components/ThemeToggle';
import './styles.css';

function App() {
  return (
    <ThemeProvider>
      <div className="App">
        <h1>Dark Mode Toggle with Context API</h1>
        <ThemeToggle />
      </div>
    </ThemeProvider>
  );
}

export default App;

Enter fullscreen mode Exit fullscreen mode

By using React's Context API, we made the dark mode state easily accessible across the app without prop-drilling. Adding localStorage ensures the theme preference persists, even after a page reload or revisit.

Feel free to tweak this basic implementation by adding more components and styles as per your needs.

If you'd like to see more of my work, check out my portfolio vrushikvisavadiya

Top comments (2)

Collapse
 
wearypossum4770 profile image
Stephen Smith

Would it be best to use a media query to respect he users preferences?

Collapse
 
visavadiyavrushik profile image
Vrushik Visavadiya

Yes, using a media query to respect the user's preferences is also best practice.