How to implement dark mode in React

Implementing dark mode in React applications improves user experience by reducing eye strain and providing visual preferences that adapt to user environments. As the creator of CoreUI with over 25 years of development experience, I’ve built theme switching systems across numerous production applications. The most effective approach is using React Context with CSS custom properties and localStorage persistence for consistent theme management. This provides seamless theme switching with proper state management and user preference persistence across browser sessions.

Use React Context with CSS custom properties and localStorage to implement persistent dark mode functionality with smooth theme transitions.

import { createContext, useContext, useState, useEffect } from 'react'

const ThemeContext = createContext()

export function ThemeProvider({ children }) {
  const [theme, setTheme] = useState('light')

  useEffect(() => {
    const savedTheme = localStorage.getItem('theme') || 'light'
    setTheme(savedTheme)
    document.documentElement.setAttribute('data-theme', savedTheme)
  }, [])

  const toggleTheme = () => {
    const newTheme = theme === 'light' ? 'dark' : 'light'
    setTheme(newTheme)
    localStorage.setItem('theme', newTheme)
    document.documentElement.setAttribute('data-theme', newTheme)
  }

  return (
    <ThemeContext.Provider value={{ theme, toggleTheme }}>
      {children}
    </ThemeContext.Provider>
  )
}

export function useTheme() {
  const context = useContext(ThemeContext)
  if (!context) {
    throw new Error('useTheme must be used within ThemeProvider')
  }
  return context
}

// Component usage
function App() {
  const { theme, toggleTheme } = useTheme()

  return (
    <div className="app">
      <header>
        <h1>Dark Mode Demo</h1>
        <button onClick={toggleTheme}>
          Switch to {theme === 'light' ? 'Dark' : 'Light'} Mode
        </button>
      </header>
      <main>
        <p>Content that adapts to theme changes</p>
      </main>
    </div>
  )
}

This implementation uses React Context to manage theme state globally, localStorage for persistence across sessions, and CSS custom properties for styling. The data-theme attribute on the document root enables CSS to respond to theme changes. The custom hook useTheme provides easy access to theme functionality throughout the component tree.

Best Practice Note:

This dark mode pattern is used in CoreUI’s theming system for consistent, professional theme switching. Consider detecting user’s system preference with prefers-color-scheme media query and implementing smooth transitions between themes for enhanced user experience.


Speed up your responsive apps and websites with fully-featured, ready-to-use open-source admin panel templates—free to use and built for efficiency.


About the Author

Subscribe to our newsletter
Get early information about new products, product updates and blog posts.
How to force a React component to re-render
How to force a React component to re-render

How to Conditionally Add a Property to an Object in JavaScript
How to Conditionally Add a Property to an Object in JavaScript

How to Open All Links in New Tab Using JavaScript
How to Open All Links in New Tab Using JavaScript

How to loop through an array in JavaScript
How to loop through an array in JavaScript

Answers by CoreUI Core Team