Dark Mode

Sisyphos UI ships light and dark themes out of the box. Flip them with one class or use the built-in helpers.

How it works

The dark theme is a CSS class, .sisyphos-theme-dark, that re-assigns the neutral token pool. Toggle the class on <html> (or any ancestor) to switch modes.

snippet.csscss
:root {
  --sisyphos-color-neutral: #f9fafb;
  /* …light values */
}

.sisyphos-theme-dark {
  --sisyphos-color-neutral: #1c1c1c;
  /* …dark values */
}

Basic toggle

Use the helpers exported from the library for imperative toggles:

snippet.tsxtsx
import { setThemeMode, toggleThemeMode } from "@sisyphos-ui/ui";

<Button onClick={() => toggleThemeMode()}>Toggle theme</Button>
<Button onClick={() => setThemeMode("dark")}>Force dark</Button>

Or manage the class yourself:

snippet.tsxtsx
document.documentElement.classList.toggle("sisyphos-theme-dark");

Respect system preference

Wire the initial mode to prefers-color-scheme and persist the user's choice:

components/theme-init.tsxtsx
"use client";

import { useEffect } from "react";
import { setThemeMode } from "@sisyphos-ui/ui";

export function ThemeInit() {
  useEffect(() => {
    const saved = localStorage.getItem("theme") as "light" | "dark" | null;
    const system = matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
    setThemeMode(saved ?? system);
  }, []);

  return null;
}

Avoid flash on load

To prevent a flash of unstyled content on first paint, inject a tiny inline script before hydration that sets the theme class synchronously.

app/layout.tsxtsx
export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en" suppressHydrationWarning>
      <head>
        <script
          dangerouslySetInnerHTML={{
            __html: `(function(){
              var saved = localStorage.getItem("theme");
              var mode = saved || (matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light");
              if (mode === "dark") document.documentElement.classList.add("sisyphos-theme-dark");
            })();`,
          }}
        />
      </head>
      <body>{children}</body>
    </html>
  );
}