How to Build a Dark Mode Toggle in React with Tailwind CSS and Local Storage

07/07/2025

How to Build a Dark Mode Toggle in React with Tailwind CSS and Local Storage

Create a professional dark mode toggle in React using Tailwind CSS, React Context, and localStorage. Perfect for scalable theming and modern UI development. Dark mode has become an essential feature in modern web applications, enhancing user experience and accessibility across devices. In this comprehensive guide, you'll learn how to implement a reusable dark mode toggle in a React + TypeScript project using Tailwind CSS and React Context. We'll cover everything from initializing a Vite project to persisting theme preferences with localStorage and designing a clean, scalable component structure. Whether you're a beginner or an advanced React developer, this tutorial will help you build a maintainable and visually consistent dark mode feature for your web apps.

Create a Dark Mode Toggle in React with Local Storage

Step-by-Step Beginner Guide to Create Dark Mode in React

  • Set up a new React project with Vite
  • Install and configure Tailwind CSS for dark mode support
  • Use React Context to manage theme state
  • Build a toggle component for switching modes
  • Persist user preference using localStorage

Step 1: Create Your React Project


# Create a new React + TypeScript project
npm create vite@latest dark-mode-toggle --template react-ts

cd dark-mode-toggle

# Install dependencies
npm install

# Install Tailwind CSS and its peer dependencies
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
        

Step 2: Configure Tailwind CSS


// tailwind.config.js
export default {
  content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
  darkMode: 'class',
  theme: {
    extend: {}
  },
  plugins: []
}
        

Then import Tailwind into your main CSS file:


// src/index.css
@tailwind base;
@tailwind components;
@tailwind utilities;
        

Folder Structure


src/
β”œβ”€β”€ components/
β”‚   └── ThemeToggle.tsx
β”œβ”€β”€ context/
β”‚   └── ThemeContext.tsx
β”œβ”€β”€ styles/
β”‚   └── colors.css
β”œβ”€β”€ App.tsx
        

Step 1: Define Color Variables


/* styles/colors.css */
:root {
  --color-bg: #ffffff;
  --color-text: #111827;
}

.dark {
  --color-bg: #111827;
  --color-text: #f9fafb;
}
        

Step 2: Create Theme Context


// context/ThemeContext.tsx
import React, { createContext, useContext, useEffect, useState } from 'react';

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

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

  useEffect(() => {
    const storedTheme = localStorage.getItem('theme');
    if (storedTheme) {
      setTheme(storedTheme);
      document.documentElement.classList.toggle('dark', storedTheme === '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: Build the Toggle Button


// components/ThemeToggle.tsx
import React from 'react';
import { useTheme } from '../context/ThemeContext';

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

  return (
    <button
      onClick={toggleTheme}
      className="px-4 py-2 rounded border border-gray-300 dark:border-gray-600 text-sm bg-white dark:bg-gray-700 text-gray-800 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-600"
    >
      {theme === 'dark' ? 'Switch to Light Mode' : 'Switch to Dark Mode'}
    </button>
  );
};

export default ThemeToggle;
        

Step 4: Wrap Your App


// App.tsx
import React from 'react';
import { ThemeProvider } from './context/ThemeContext';
import ThemeToggle from './components/ThemeToggle';
import './styles/colors.css';

function App() {
  return (
    <ThemeProvider>
      <div className="min-h-screen bg-[var(--color-bg)] text-[var(--color-text)] flex flex-col items-center justify-center">
        <h1 className="text-3xl font-bold mb-4">React Dark Mode Toggle</h1>
        <ThemeToggle />
      </div>
    </ThemeProvider>
  );
}

export default App;
        
  • CSS variable-driven
  • Context-powered for flexibility
  • Persisted via local storage

Start small, refactor often. By separating colors and logic, you can scale your dark mode support across complex apps while keeping code readable and maintainable.