Skip to main content
Features

Dark Mode in React

CSS-only dark mode — no JS provider, no flash, no FOUC. Toggle the .dark class and the entire app re-themes.

// Toggle dark mode — just toggle a class
function ThemeToggle() {
  const [dark, setDark] = useState(false);
  return (
    <button onClick={() => {
      document.documentElement.classList.toggle("dark");
      setDark(!dark);
    }}>
      {dark ? "🌙" : "☀️"}
    </button>
  );
}

Key features

No JavaScript theme provider — dark mode is pure CSS

No flash of wrong theme — CSS applies before React hydrates

No FOUC (Flash of Unstyled Content)

Toggle via .dark class on <html> — works with any toggle mechanism

All 5 theme presets include dark mode variants

Respects prefers-color-scheme with a tiny inline script

The flash problem

JavaScript-based dark mode has a flash problem: the browser renders the page with the default (light) theme, then React hydrates and switches to dark. Users see a flash of light theme before the dark theme applies.

Ninna UI solves this with a tiny inline script in <head> that checks localStorage and adds the .dark class before any content renders. The script is 200 bytes and runs synchronously — no flash.

The theme-init script

Add this script to your <head> to prevent dark mode flash:

// public/theme-init.js — included in <head> before React loads
(function() {
  var theme = localStorage.getItem("theme");
  if (theme === "dark" || (!theme && matchMedia("(prefers-color-scheme: dark)").matches)) {
    document.documentElement.classList.add("dark");
  }
})();

Component Docs

FAQ