Theming
The tokens, the dark scheme, radius, shadows and motion, and how to retheme the whole library.
Forme has no theme object and no theme provider. The whole library reads CSS variables, and retheming it means editing those variables. That is the point: the entire visual language is about fifteen lines of CSS you can read in one screen.
The slots#
| Token | What it is |
|---|---|
--background --foreground | The page. |
--card --popover | Raised surfaces, for panels that need to read as above the page. |
--primary --secondary | Filled actions. Ink carries primary, because a filled button should read as a decision. |
--muted --accent | Quiet fills: table stripes, hover states, tabs. |
--brand --brand-strong --brand-subtle | The one chromatic colour. Links, focus, selection, data. Functional only. |
--border --input --ring | Hairlines. Structure, never the only signal for a state. |
--destructive --success --warning | Status, used sparingly. |
Dark mode#
Dark mode is a class on html, and the values live in a .dark block. No JavaScript is required for the CSS to work:
.dark {
--background: oklch(16.5% 0.002 265);
--foreground: oklch(96% 0.001 265);
/* ... */
}A retheme#
Because it is only variables, a retheme is a replacement block. This is a warmer, slightly softer dark scheme, applied by editing .dark:
.dark {
--background: oklch(19% 0.008 70);
--foreground: oklch(95% 0.006 70);
--primary: oklch(95% 0.006 70);
--primary-foreground: oklch(20% 0.008 70);
--brand: oklch(74% 0.11 60);
--radius: 0.75rem;
}Every component follows, including components you copied weeks ago, because they were reading variables rather than hard-coded values.
Radius, shadows and motion#
--radius is the single knob. Foundation derives the rest:
--radius-xs: calc(var(--radius) - 4px);
--radius-sm: calc(var(--radius) - 2px);
--radius-md: var(--radius);
--radius-lg: calc(var(--radius) + 2px);
--radius-xl: calc(var(--radius) + 6px);Shadows describe height rather than decoration, and motion is fast enough to feel mechanical:
| Variable | Value |
|---|---|
--duration-instant | 90ms |
--duration-fast | 150ms |
--duration-standard | 240ms |
--ease-standard | cubic-bezier(0.2, 0, 0, 1) |
--ease-entrance | cubic-bezier(0.16, 1, 0.3, 1) |
Foundation also sets prefers-reduced-motion to near-zero durations globally, so motion is already handled for anyone who has asked their system to stop it.
Rules worth keeping#
Colour comes from tokens. Never write a raw #hex, rgb() or arbitrary colour into a component: that value is the one thing no theme, dark mode or rebrand can reach.