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