50% off all plans with SPRING50
react Advanced

React Dark Mode hook

React Dark Mode hook
Photo by Alex Andrews on Pexels
React Dark Mode Hook
Interactive editor — edit code and see live results Open in Editor

Switch themes

import { useEffect, useState } from "react";

const useDarkMode = () => {
  const [isDarkMode, setIsDarkMode] = useState(
    () => localStorage.getItem("darkMode") === "true"
  );

  const toggle = () => setIsDarkMode((prev) => !prev);

  useEffect(() => {
    localStorage.setItem("darkMode", isDarkMode);
    if (isDarkMode) {
      document.body.classList.add("dark-mode");
    } else {
      document.body.classList.remove("dark-mode");
    }
  }, [isDarkMode]);

  return { isDarkMode, toggle };
};

export default useDarkMode;
  • useState is initialized with a lazy initializer that reads from localStorage, so the theme preference persists across page reloads.
  • toggle flips the boolean state using the functional updater (prev) => !prev.
  • useEffect runs whenever isDarkMode changes, syncing the value to localStorage and toggling a dark-mode CSS class on document.body.
import useDarkMode from "./useDarkMode";

export default function App() {
  const { isDarkMode, toggle } = useDarkMode();

  return (
    <div className={isDarkMode ? "dark" : "light"}>
      <h1>{isDarkMode ? "Dark Mode" : "Light Mode"}</h1>
      <button onClick={toggle}>
        Switch to {isDarkMode ? "Light" : "Dark"} Mode
      </button>
    </div>
  );
}
  • The App component destructures isDarkMode and toggle from the custom hook.
  • A conditional class name and heading text reflect the current theme.
  • The button calls toggle on click to switch between light and dark modes.

Summary

  • useDarkMode encapsulates all dark mode logic: state management, persistence via localStorage, and DOM class toggling.
  • The hook is reusable across any component or project that needs theme switching.
  • Using localStorage ensures the user’s preference survives page refreshes and new sessions.
  • The useEffect hook keeps the DOM in sync with the React state, applying or removing the dark-mode class on the body element.

Try this in our interactive code editor

Practice hands-on with our built-in code sandbox.

Open Code Editor
Adrian Bigaj
Adrian Bigaj

Creator of BigDevSoon

Full-stack developer and educator passionate about helping developers build real-world skills through hands-on projects. Creator of BigDevSoon, a vibe coding platform with 21 projects, 100 coding challenges, 40+ practice problems, and Merlin AI.