x
Back to Blogs
Jan 5, 2025

Implementing Dark Mode in React

Dark mode has become an essential feature for modern web applications. Let’s explore how to implement it properly with React.

Why Dark Mode Matters#

  • Reduces eye strain in low-light environments
  • Saves battery on OLED screens
  • User preference and accessibility
  • Modern, polished feel

CSS Variables Example#

Define theme colors as CSS variables:

:root { --bg-primary: #ffffff; --bg-secondary: #f3f4f6; --text-primary: #111827; --text-secondary: #6b7280; --border: #d1d5db; } [data-theme='dark'] { --bg-primary: #1f2937; --bg-secondary: #374151; --text-primary: #f3f4f6; --text-secondary: #9ca3af; --border: #4b5563; } body { background-color: var(--bg-primary); color: var(--text-primary); transition: background-color 0.3s ease, color 0.3s ease; }

React Context Implementation#

import { createContext, useContext, useState, useEffect } from 'react' const ThemeContext = createContext() export function ThemeProvider({ children }) { const [theme, setTheme] = useState('light') useEffect(() => { // Load saved theme const savedTheme = localStorage.getItem('theme') if (savedTheme) { setTheme(savedTheme) } else { // Use system preference const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches setTheme(prefersDark ? 'dark' : 'light') } }, []) useEffect(() => { // Apply theme to document document.documentElement.setAttribute('data-theme', theme) localStorage.setItem('theme', theme) }, [theme]) const toggleTheme = () => { setTheme(prev => prev === 'light' ? 'dark' : 'light') } 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 }

Usage in Components#

function Header() { const { theme, toggleTheme } = useTheme() return ( <header> <h1>My App</h1> <button onClick={toggleTheme}> {theme === 'light' ? '🌙' : '☀️'} </button> </header> ) }

Detecting System Preference#

Listen to system theme changes:

useEffect(() => { const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)') const handleChange = (e) => { if (e.matches) { setTheme('dark') } else { setTheme('light') } } mediaQuery.addEventListener('change', handleChange) return () => mediaQuery.removeEventListener('change', handleChange) }, [])

Preventing Flash of Unstyled Content#

Add a script in your HTML <head> to set theme before render:

<script> (function() { const theme = localStorage.getItem('theme') || (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') document.documentElement.setAttribute('data-theme', theme) })() </script>

TailwindCSS Dark Mode#

If using Tailwind, enable dark mode in config:

// tailwind.config.js module.exports = { darkMode: 'class', // or 'media' for system preference // ... other config }

Usage:

<div className="bg-white dark:bg-gray-900 text-black dark:text-white"> This text changes color based on theme </div>

Best Practices#

  1. Respect user preference - Check system settings first
  2. Persist choice - Save to localStorage
  3. Smooth transitions - Use CSS transitions for theme changes
  4. Test contrast ratios - Ensure accessibility in both modes
  5. Consider images - Provide different versions for each theme if needed

Conclusion#

Dark mode is more than just inverting colors. A thoughtful implementation respects user preferences, maintains accessibility, and enhances the overall user experience!

Related

Mastering CSS Grid Layout

Dive deep into CSS Grid and learn how to create complex layouts with ease.

Jan 28, 2025

Web Accessibility Fundamentals

Essential accessibility practices every web developer should know to build inclusive web applications.

Jan 20, 2025

Understanding React State Management

Learn React state management fundamentals with examples and explore when to use Context API vs external libraries.

Jan 18, 2025

Getting Started with React Hooks

A comprehensive guide to understanding and using React Hooks in your applications.

Jan 15, 2025