Dark Mode Toggle in React
Dark mode is a theme selector that enhances user engagement by respecting their preferred theme.
Overview
In this blog, we will cover how to toggle between two themes: light and dark. (Multi-theme selection will be covered in upcoming blogs.)
UI Component
We will create a reusable UI component, a button that can be placed anywhere in the application while maintaining the same functionality.
Toggle Button UI
<div className="relative w-14 h-8 rounded-3xl bg-slate-300 dark:bg-zinc-700 place-center cursor-pointer" > <div className="absolute top-1 rounded-full w-6 h-6 bg-blue-500" /> </div> In global.css or index.css
The following styles help integrate Tailwind CSS and define a custom variant for dark mode:
@import 'tailwindcss'; /* Define a custom variant for dark mode */ @custom-variant dark (&:is(.dark *)); -
@import 'tailwindcss';Loads Tailwind CSS into your global styles. -
@custom-variant dark (&:is(.dark *));- Creates a custom Tailwind variant named
dark. - Uses
:is(.dark *)to apply styles when any parent element has the.darkclass. - Ensures that child elements automatically inherit dark mode styles.
- Creates a custom Tailwind variant named
Creating a Custom Hook for Toggling Dark Mode
We will now create a custom hook, useDarkMode, to handle dark mode toggling.
Custom Hook: useDarkMode
import { useState, useEffect, useCallback } from "react"; export default function useDarkMode() { const [isDarkMode, setIsDarkMode] = useState<boolean>(() => { const savedTheme = localStorage.getItem("theme"); if (savedTheme) { return savedTheme === "dark"; } return window.matchMedia("(prefers-color-scheme: dark)").matches; }); // Toggle dark mode const toggleDarkMode = useCallback(() => { setIsDarkMode((prev) => { const newMode = !prev; const html = document.documentElement; if (newMode) { html.classList.add("dark"); localStorage.setItem("theme", "dark"); } else { html.classList.remove("dark"); localStorage.setItem("theme", "light"); } return newMode; }); }, []); // Sync the theme with the <html> element useEffect(() => { const html = document.documentElement; if (isDarkMode) { html.classList.add("dark"); } else { html.classList.remove("dark"); } }, [isDarkMode]); return { isDarkMode, toggleDarkMode }; } Explanation of useDarkMode
- State Initialization: It first checks
localStoragefor a saved theme preference. If none exists, it defaults to the system theme preference. - Toggling Theme: The
toggleDarkModefunction switches the theme, updates thehtmlclass, and stores the new theme inlocalStorage. - Effect Hook: Ensures the theme remains synced with the
htmlelement when the component renders.
Using the Hook in a Component
Now, we will use useDarkMode in a component to toggle dark mode.
ToggleDarkMode Component
import useDarkMode from "../../../hooks/useDarkMode"; export default function ToggleDarkMode() { const { toggleDarkMode, isDarkMode } = useDarkMode(); return ( <div onClick={toggleDarkMode} className="relative w-14 h-8 rounded-3xl bg-slate-300 dark:bg-zinc-700 place--center cursor-pointer" > <div className={`absolute top-1 rounded-full w-6 h-6 bg-blue-500 ${isDarkMode ? "left-1" : "right-1"}`} /> </div> ); } Explanation
- Imports
useDarkModeHook: ExtractstoggleDarkModeandisDarkModefrom the hook. - UI Structure: A switch-like button that changes its position based on
isDarkMode. - Click Handler: Calls
toggleDarkModeto switch themes.
Using in Your App
Now you can import and use <ToggleDarkMode /> anywhere in your application!
Example: Using It in a Navbar
import ToggleDarkMode from "./components/ToggleDarkMode"; export default function Navbar() { return ( <nav className="flex justify-between items-center p-4 bg-white dark:bg-black"> <h1 className="text-xl font-bold text-gray-900 dark:text-white">My Website</h1> <ToggleDarkMode /> </nav> ); } Demo
Check out the live demo: Dark Mode Toggle
Top comments (0)