Themes
Five palettes over one set of components. Each theme authors 30 values; the 69 semantic names every component reads stay the same, so swapping a theme never touches component source. Below is every shipped palette, light and dark.
Compare
Solace
$ npx @beaket/ui init --theme solaceWarm paper, cool ink. The default: equal-weight signals under one vivid blue.
Porcelain
$ npx @beaket/ui init --theme porcelainNear-white paper and cool graphite, with the deepest accent in the set.
Tobacco
$ npx @beaket/ui init --theme tobaccoWarm earthen paper and quiet low-chroma signals. Its sheets step lighter than the page.
Marigold
$ npx @beaket/ui init --theme marigoldPure-grey paper and ink carrying deliberately loud signals.
Eucalyptus
$ npx @beaket/ui init --theme eucalyptusCool-blue paper and blue-black ink, vivid throughout. Its sheets also step lighter.
Try one here
This picker repaints the whole documentation site, including the specimen below, so you can read a theme in a real interface before installing it.
Revenue
$12,840
Users
1,284
| Order | Customer | Status |
|---|---|---|
| #1042 | Sofia Martinez | Shipped |
| #1041 | Liam O'Connor | Pending |
| #1040 | Aisha Rahman | Failed |
| #1039 | Noah Williams | Shipped |
Overview
Settings
Every theme supplies 30 palette values and inherits the same 69 semantic names. The CLI also installs the shared type, spacing, border, and radius foundation. Components consume 28 palette values through the semantic layer; --tone-8 and --tone-9 are reserved for neutral-ramp compatibility and future deep-ink roles.
The CLI writes the foundation, semantic layer, and selected palette directly into the CSS file you choose during setup.
npx @beaket/ui init --theme solace
# Later, switch the saved project to another theme
npx @beaket/ui theme --theme tobaccoDark mode
Every theme ships with a dark twin. Once the CLI has written the tokens, dark mode works automatically — no flags, no extra imports, no toggle configuration required.
How it works
The CSS written by the CLI contains both light and dark values. With no data-theme attribute on <html>, @media (prefers-color-scheme: dark) follows the OS. Set data-theme="light" or data-theme="dark" to force a scheme; remove the attribute for system mode. Your app owns persistence and applying the attribute before first paint, for example through a cookie read by your server layout.
document.documentElement.dataset.theme = "dark";
document.documentElement.dataset.theme = "light";
delete document.documentElement.dataset.theme; // systemCustomize safely
The marked block is managed: theme regenerates it. Put brand overrides in the generated stub after beaket:theme:end. Keep its explicit light, system-dark and forced-dark selectors: plain :root has lower specificity than the generated dark selectors. The stub is emitted once and preserved on later syncs.
npx @beaket/ui theme --theme tobacco --diff
npx @beaket/ui theme --theme tobacco --dry-run
# Review, then apply (confirmation defaults to No)
npx @beaket/ui theme --theme tobaccoBoth preview flags leave CSS, config and backups untouched. A stored managed-block hash detects local edits; replacement saves a numbered backup. --overwrite explicitly skips confirmation. Generated CSS also honors prefers-reduced-motion, shortening animations and transitions, including pseudo-elements. Spacing uses Tailwind's existing 4px utility scale, not a separate custom scale.
Docs preview controls
The theme picker in this documentation site is a local preview implementation, not an @beaket/ui CSS API. It reads theme from the URL and beaket-theme / beaket-color-scheme from this site's localStorage, then injects the generated token values onto the document before paint. Those keys affect this documentation site only; importing a package palette does not read them.
The consumer contract is the root data-theme attribute in CLI-generated CSS, not this site's storage keys. Raw source palettes remain the light/dark authoring inputs.