Menu

Dark mode

One attribute on the html element switches every theme between light and dark.

How it works

Set data-theme="dark" on the html element. Every colour token switches to its dark value and the components follow, including their animations.

index.html
<html lang="en" data-theme="dark">

Every theme ships both sets of tokens in the same file, so there is nothing extra to install. A dark class on html works too.

Add a toggle

The theme only reads the attribute. Remembering the choice is up to your app. This button saves it in localStorage.

src/theme-toggle.tsx
import { useEffect, useState } from "react";
import { Button } from "./components/ui/button";

export function ThemeToggle() {
  const [mode, setMode] = useState("light");
  useEffect(() => {
    setMode(document.documentElement.getAttribute("data-theme") === "dark" ? "dark" : "light");
  }, []);

  function toggle() {
    const next = mode === "dark" ? "light" : "dark";
    document.documentElement.setAttribute("data-theme", next);
    localStorage.setItem("mode", next);
    setMode(next);
  }

  return (
    <Button variant="outline" onClick={toggle}>
      {mode === "dark" ? "Switch to light" : "Switch to dark"}
    </Button>
  );
}

Follow the system setting

Put a small script in the head of your page. It uses the saved choice, or the visitor's system setting when nothing is saved, and runs before the first paint so the page never flashes the wrong colours.

index.html
<script>
  var mode = localStorage.getItem("mode");
  if (!mode) mode = matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
  document.documentElement.setAttribute("data-theme", mode);
</script>

Try it

This changes the whole site, not only the box.

The html element now has data-theme="light".

Dark styles in your own code

Use the semantic classes, such as bg-surface and text-fg-primary. They change by themselves, so most of your code needs no dark rules.

When you do need one, the Tailwind dark: variant is wired to the same attribute.

tsx
<div className="bg-surface dark:bg-subtle">…</div>
The list of tokens and what they map to is on the theming page.
esc

↑↓ to navigate · ↵ to select · esc to close