React 2 min read 825 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.

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!

Related Articles

Related Articles

Need Help With Your Project?

Book a free 30-minute consultation to discuss your technical challenges and explore solutions together.