Files
skills/docs/ui/react/react-ui/src/theme/themes/dark.md
2026-05-29 08:20:56 +01:00

2.5 KiB

darkTheme — pure inversion of lightTheme

Purpose

The dark counterpart of lightTheme. Same variant surface, same token names, lightness anchors inverted so foreground reads on backgrounds and vice versa. Ships as one of the three built-in themes for the chassis so consumers can offer a light/dark toggle out-of-the-box without authoring any tokens themselves.

Features

  • Inverted lightness anchors: white-ish foreground on near-black background, secondary / muted ramped through oklch(0.269 0 0)
  • WCAG AA at default sizes (foreground vs background contrast > 4.5:1)
  • colorScheme: 'dark' so the chassis FOUC-prevention script applies data-theme="dark" when prefers-color-scheme: dark is the system default and the user has not overridden via the storage key
  • Same respectReducedMotion: 'strict' policy as lightTheme

Usage: Basic example

import { ReactUiProvider } from "@suaveplan/react-ui/provider";
import { darkTheme } from "@suaveplan/react-ui/theme/themes/dark";

<ReactUiProvider
    i18n={i18n}
    themes={[darkTheme]}
    defaultTheme="dark"
>
    <YourApp />
</ReactUiProvider>;

Usage: Advanced example

import { lightTheme, darkTheme } from "@suaveplan/react-ui/theme";

// Pair with the matching `<ThemeSwitcher>` so users can toggle:
import { ThemeSwitcher } from "@suaveplan/react-ui/theme/theme-switcher";

<ReactUiProvider themes={[lightTheme, darkTheme]} defaultTheme="dark" i18n={i18n}>
    <ThemeSwitcher>
        {({ themes, current, setTheme }) => (
            <select
                value={current.name}
                onChange={(e) => setTheme(e.target.value)}
            >
                {themes.map((t) => (
                    <option key={t.name} value={t.name}>
                        {t.name}
                    </option>
                ))}
            </select>
        )}
    </ThemeSwitcher>
</ReactUiProvider>;

API Reference

  • darkTheme: ThemePlugin<'dark'> — the named export.
  • Same shape as lightTheme; only the lightness anchors differ.

Implementation notes

The implementation deliberately avoids deriving the dark tokens from the light tokens at runtime — that would couple the two themes and make per-token tweaks awkward. Each theme is a hand-written object literal so a designer can adjust dark-only contrast without leaking into light's palette. The variant-key parity with lightTheme is asserted by themes.test.ts so a future drift in either theme fails CI before it ships.