Dark mode is no longer just a design trend—it’s an expected user feature. Whether you’re building a portfolio, a blog, or a dashboard, giving users the ability to switch between light and dark themes improves accessibility and reduces eye strain. The good news? You don’t need complex state management or third-party libraries. In this tutorial, I’ll show you how to add dark mode to a React app in 15 minutes using the React Context API and CSS custom properties. By the end, you’ll have a theme toggle that persists user preferences and respects system settings.

Why Dark Mode Matters for React Apps in 2026

Studies show that over 80% of smartphone users enable dark mode when available. Modern operating systems (iOS, Android, Windows, and macOS) all support system-wide dark mode. When you learn to add dark mode to a React app in 15 minutes, you’re not just following a trend—you’re improving user retention and accessibility. Plus, it’s surprisingly simple with React’s built-in tools.

What You’ll Need

  • A basic React app (created with Vite create-react-app Vite or Next.js).

  • Node.js installed.

  • 15 minutes of focused time.

We’ll use two approaches: the Context API + CSS variables (library-agnostic) and a quick Tailwind CSS method. Pick the one that fits your stack.

Approach 1: Context API + CSS Custom Properties (Universal)

This method works with plain CSS, Sass, or any styling library.

Step 1: Create a Theme Context

Inside your src folder, create a file called

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

const ThemeContext = createContext();

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

export const ThemeProvider = ({ children }) => {
  const [darkMode, setDarkMode] = useState(false);

  // Check system preference or localStorage on mount
  useEffect(() => {
    const savedTheme = localStorage.getItem('theme');
    const systemPrefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
    
    if (savedTheme === 'dark' || (!savedTheme && systemPrefersDark)) {
      setDarkMode(true);
      document.documentElement.setAttribute('data-theme', 'dark');
    } else {
      setDarkMode(false);
      document.documentElement.setAttribute('data-theme', 'light');
    }
  }, []);

  const toggleTheme = () => {
    const newMode = !darkMode;
    setDarkMode(newMode);
    const theme = newMode ? 'dark' : 'light';
    document.documentElement.setAttribute('data-theme', theme);
    localStorage.setItem('theme', theme);
  };

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

Step 2: Add CSS Variables

In your main CSS file (e.g., index.css or App.css), define light and dark variables:

:root {
  --bg-color: #ffffff;
  --text-color: #1a1a1a;
  --card-bg: #f5f5f5;
}

[data-theme="dark"] {
  --bg-color: #121212;
  --text-color: #e0e0e0;
  --card-bg: #1e1e1e;
}

body {
  background-color: var(--bg-color);
  color: var(--text-color);
  transition: background-color 0.3s ease, color 0.2s ease;
}

Step 3: Wrap Your App and Use the Toggle

In index.js or wrap your app with the

import { ThemeProvider } from './ThemeContext';

ReactDOM.render(
  <ThemeProvider>
    <App />
  </ThemeProvider>,
  document.getElementById('root')
);

Now create a toggle button anywhere in your components:

import { useTheme } from './ThemeContext';

function DarkModeToggle() {
  const { darkMode, toggleTheme } = useTheme();
  return (
    <button onClick={toggleTheme}>
      Switch to {darkMode ? 'Light' : 'Dark'} Mode
    </button>
  );
}

That’s it! In less than 15 minutes, you’ve learned how to add dark mode to a React app in 15 minutes using only React’s Context API and CSS variables.

Approach 2: Dark Mode with Tailwind CSS (Even Faster)

If your React app uses Tailwind CSS, dark mode is built-in. First, enable dark mode in tailwind.config.js:

module.exports = {
  darkMode: 'class', // or 'media' to follow system preference
  // ...rest of config
}

Then, in your main layout component, add a toggle that toggles the dark class on the html element:

const [dark, setDark] = useState(false);

useEffect(() => {
  if (dark) {
    document.documentElement.classList.add('dark');
    localStorage.setItem('theme', 'dark');
  } else {
    document.documentElement.classList.remove('dark');
    localStorage.setItem('theme', 'light');
  }
}, [dark]);

// Toggle function
const toggleDark = () => setDark(!dark);

Now use Tailwind’s dark: modifier in your components:

<div className="bg-white dark:bg-gray-900 text-black dark:text-white">
  <h1 className="text-2xl">My App</h1>
  <button onClick={toggleDark}>Toggle Dark Mode</button>
</div>

For more Tailwind dark mode patterns, check the external resource: Tailwind CSS Dark Mode Documentation.

Approach 3: Using Material UI (MUI) Theme Provider

If you’re using MUI v5, dark mode is even simpler:

import { createTheme, ThemeProvider, useMediaQuery } from '@mui/material';
import { useState, useMemo } from 'react';

function App() {
  const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)');
  const [mode, setMode] = useState(prefersDarkMode ? 'dark' : 'light');
  
  const theme = useMemo(() => createTheme({
    palette: { mode },
  }), [mode]);

  return (
    <ThemeProvider theme={theme}>
      <Button onClick={() => setMode(mode === 'light' ? 'dark' : 'light')}>
        Toggle Dark Mode
      </Button>
      {/* rest of app */}
    </ThemeProvider>
  );
}

For a deeper dive into React theme management, read our internal guide on advanced React context patterns for larger applications.

Comparison Table: Which Method Should You Use?

Method Time Dependencies Best For
Context API + CSS vars 10-15 min None (vanilla React) Custom CSS, any stack
Tailwind CSS 5 min Tailwind Projects already using Tailwind
Material UI 5 min MUI Apps with MUI design system

Persisting User Preference

All three methods above are used localStorage to remember the user’s choice across page reloads. The Context API example already includes this. For the Tailwind approach, add the same thing useEffect that reads localStorage on initial load.

Handling System Preference Changes

To respect the user’s OS setting, you can listen to the prefers-color-scheme media query. The Context API example does this via the For a production-ready hook, consider using the external resource: useDarkMode hook from useHooks—it handles localStorage, system preference, and SSR gracefully.

Conclusion

Adding dark mode to a React application doesn’t require bloated libraries or complicated state management. With the Context API and CSS custom properties, you can add dark mode to a React app in 15 minutes or less. If you’re using Tailwind or Material UI, it’s even faster. The key is to start simple: a toggle, a context or class toggle, and persistent storage.

Now open your React project and give your users the gift of dark mode. Your eyes (and your users’ eyes) will thank you.

For more React performance and UX tips, explore our internal collection of React best practices for 2026. If you need help customizing your React project or have questions, feel free to contact us here.