How to Handle Dark Mode in Next.js: Simple and Effective Approach
dark mode in Next.js, use React state or context to toggle a CSS class on the html or body element and apply styles accordingly. Use useEffect to sync the theme with user preferences or saved settings for a smooth experience.Why This Happens
Many beginners try to toggle dark mode by directly changing styles without syncing with React state or without applying the theme class to the right HTML element. This causes the UI not to update or flicker on page load.
import { useState } from 'react'; export default function Home() { const [darkMode, setDarkMode] = useState(false); return ( <div> <button onClick={() => setDarkMode(!darkMode)}> Toggle Dark Mode </button> <div style={{ backgroundColor: darkMode ? 'black' : 'white', color: darkMode ? 'white' : 'black' }}> Hello World </div> </div> ); }
The Fix
Use React useEffect to add a dark class to the html element. This lets CSS handle the theme globally. Also, check the user's system preference on load and save the choice in localStorage to remember it.
import { useState, useEffect } from 'react'; export default function Home() { const [darkMode, setDarkMode] = useState(false); useEffect(() => { // Check saved theme or system preference const saved = localStorage.getItem('theme'); if (saved === 'dark' || (!saved && window.matchMedia('(prefers-color-scheme: dark)').matches)) { setDarkMode(true); document.documentElement.classList.add('dark'); } else { document.documentElement.classList.remove('dark'); } }, []); useEffect(() => { if (darkMode) { document.documentElement.classList.add('dark'); localStorage.setItem('theme', 'dark'); } else { document.documentElement.classList.remove('dark'); localStorage.setItem('theme', 'light'); } }, [darkMode]); return ( <div> <button onClick={() => setDarkMode(!darkMode)}> Toggle Dark Mode </button> <div className="content"> Hello World </div> <style jsx>{` .content { background-color: white; color: black; padding: 20px; transition: background-color 0.3s, color 0.3s; } .dark .content { background-color: #121212; color: #e0e0e0; } `}</style> </div> ); }
Prevention
Always manage dark mode state in React and apply a global CSS class to the html or body element. Use localStorage to remember user choice and prefers-color-scheme media query to respect system settings. Avoid inline styles for themes to keep CSS maintainable and transitions smooth.
Related Errors
Flickering on page load: Happens if theme class is added after React hydration. Fix by adding initial theme class in _document.js or inline script.
Theme not persisting: Forgetting to save or read from localStorage causes theme to reset on refresh.