React 2 min read 776 views

How to Implement Dark Mode in React with Tailwind CSS

Add dark mode support to your React application with Tailwind CSS and persistent user preferences.

E
Dark mode interface

Step 1: Configure Tailwind

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

Step 2: Create Theme Provider

'use client';

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

const ThemeContext = createContext({
    theme: 'light',
    toggleTheme: () => {},
});

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

    useEffect(() => {
        // Check localStorage or system preference
        const saved = localStorage.getItem('theme');
        const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;

        const initial = saved || (prefersDark ? 'dark' : 'light');
        setTheme(initial);
        document.documentElement.classList.toggle('dark', initial === 'dark');
    }, []);

    const toggleTheme = () => {
        const newTheme = theme === 'light' ? 'dark' : 'light';
        setTheme(newTheme);
        localStorage.setItem('theme', newTheme);
        document.documentElement.classList.toggle('dark', newTheme === 'dark');
    };

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

export const useTheme = () => useContext(ThemeContext);

Step 3: Theme Toggle Button

'use client';

import { useTheme } from './ThemeProvider';

export function ThemeToggle() {
    const { theme, toggleTheme } = useTheme();

    return (
        <button
            onClick={toggleTheme}
            className="p-2 rounded-lg bg-gray-200 dark:bg-gray-700"
        >
            {theme === 'light' ? '🌙' : '☀️'}
        </button>
    );
}

Step 4: Use Dark Classes

<div className="bg-white dark:bg-gray-900">
    <h1 className="text-gray-900 dark:text-white">
        Hello World
    </h1>
    <p className="text-gray-600 dark:text-gray-300">
        This changes based on theme
    </p>
</div>

Step 5: Prevent Flash

// Add to <head> in layout
<script dangerouslySetInnerHTML={{
    __html: `
        (function() {
            const theme = localStorage.getItem('theme') ||
                (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
            document.documentElement.classList.toggle('dark', theme === 'dark');
        })();
    `
}} />
Share this article:
ES

Written by Edrees Salih

Full-stack software engineer with 9 years of experience. Passionate about building scalable solutions and sharing knowledge with the developer community.

View Profile

Comments (0)

Leave a Comment

Your email will not be published.

No comments yet. Be the first to share your thoughts!