Theming
Colour resolves in CSS, before React runs. A Theme is the light or dark rendering of the active Skin; a Skin is one CSS file that rewrites brand tokens and nothing else.
Selecting a theme
data-theme on the document root wins in both directions; with no attribute the page follows
prefers-color-scheme. ThemeProvider only writes that attribute — it never holds colour.
Use the toggle at the top right of this page — it is this exact hook.
import { ThemeProvider, useTheme } from '@ceebee/ui/client';
export default function Layout({ children }) {return <ThemeProvider defaultChoice="system">{children}</ThemeProvider>;}
function ThemeToggle() {const { choice, setChoice, resolved } = useTheme();return <Button onClick={() => setChoice(resolved === 'dark' ? 'light' : 'dark')}>{resolved}</Button>;}Writing a Skin
A Skin rewrites skin tokens only. It never touches structure tokens and never writes a component rule; if a Skin needs a rule, the component is missing a token.
The optional clarity.css Skin is the content-first glass direction for CeeBee products. Load it
after styles.css; it tunes both regular and clear materials while preserving the same component
API and accessibility fallbacks.
import '@ceebee/ui/styles.css';import '@ceebee/ui/skins/clarity.css';tinted · violet
glass
gradient · blue
/* skins/astra.css — the violet-gradient dashboard look */:root {--cb-hue-brand: 278;--cb-bg: oklch(0.97 0.02 285);--cb-surface: oklch(1 0 0 / 0.86);--cb-tint-strength: 0.12;--cb-glass-blur: 40px;}
:root[data-theme="dark"] {--cb-bg: oklch(0.21 0.04 285);--cb-surface: oklch(0.27 0.045 285);}Do
Put a project's brand in a Skin file and load it after the base stylesheet.
Don't
Override component classes in the consuming app — that is a token the library is missing, and a fork waiting to happen.
More contrast
prefers-contrast: more steps the borders and the secondary text up without changing hue, so
someone who asked their system for stronger contrast gets it from the tokens rather than from a
separate theme you have to maintain.
Runtime colour
If a person picks their own accent colour, write the value into the custom property and leave the tokens where they are:
Tokens stay in CSS; JavaScript only supplies a value.
<div style={{ '--cb-hue-brand': userHue }}>{children}</div>