Theming
GuideAll visual decisions live in CSS custom properties. Override any token to restyle the entire system without touching component code.
Dark & Light mode
Forma is dark-first. The default :root defines a dark palette. To switch to light mode, add data-theme="light" on <html>:
<html data-theme="light"> To persist the user's preference across sessions, store it in localStorage under the key forma-theme and read it synchronously before paint:
index.html — inline script in <head>
;(function () {
const t = localStorage.getItem('forma-theme')
if (t) document.documentElement.setAttribute('data-theme', t)
})() Custom theme
Add a new data-theme value to create a third palette (e.g. brand, high-contrast):
[data-theme="brand"] {
--color-bg-base: #0f0a1e;
--color-bg-surface-1: #1a1030;
--color-text-primary: #c4b5fd;
--color-brand: #8b5cf6;
--color-brand-bg: #8b5cf6;
--color-brand-fg: #ffffff;
} Token reference
Backgrounds
| CSS variable | Tailwind class | Dark default | Role |
|---|---|---|---|
--color-bg-base | bg-bg-base | #090909 | Page canvas |
--color-bg-surface-1 | bg-bg-surface-1 | #111111 | Cards, sidebars, nav |
--color-bg-surface-2 | bg-bg-surface-2 | #181818 | Inputs, dropdowns, code blocks |
--color-bg-surface-3 | bg-bg-surface-3 | #202020 | Hover fills, selected rows |
--color-bg-overlay | bg-bg-overlay | rgba(0,0,0,.72) | Dialog/drawer backdrop |
Text
| CSS variable | Tailwind class | Dark default | Role |
|---|---|---|---|
--color-text-primary | text-text-primary | #f0f0f0 | Headings, body |
--color-text-secondary | text-text-secondary | rgba(240,240,240,.52) | Supporting copy |
--color-text-muted | text-text-muted | rgba(240,240,240,.22) | Labels, counters |
--color-text-disabled | text-text-disabled | rgba(240,240,240,.28) | Disabled states |
--color-text-inverted | text-text-inverted | #090909 | Text on primary bg |
Borders
| CSS variable | Tailwind class | Dark default | Role |
|---|---|---|---|
--color-border-subtle | border-border-subtle | rgba(255,255,255,.07) | Dividers, card edges |
--color-border-default | border-border-default | rgba(255,255,255,.13) | Input borders |
--color-border-strong | border-border-strong | rgba(255,255,255,.22) | Focus, active rings |
Border Radius
| CSS variable | Tailwind class | Value | Usage |
|---|---|---|---|
--radius-sm | rounded-sm | 2px | Buttons, inputs (site-wide default) |
--radius-md | rounded-md | 4px | Cards, dropdowns, popovers |
--radius-lg | rounded-lg | 8px | Dialogs, drawers |
--radius-xl | rounded-xl | 12px | Large panels |
--radius-full | rounded-full | 9999px | Pills, badges, switch tracks |
Typography
| CSS variable | Tailwind class | Value | Role |
|---|---|---|---|
--font-display | font-display | Syne, system-ui | Headings, logotype |
--font-body | font-body | DM Sans, system-ui | UI text, body copy |
--font-mono | font-mono | DM Mono, Fira Code | Code blocks |
Semantic
| CSS variable | Default | Siblings |
|---|---|---|
--color-error | #ff6b6b | --color-error-bg, --color-error-border |
--color-success | #4dff91 | --color-success-bg, --color-success-border |
--color-warning | #ffb74d | --color-warning-bg, --color-warning-border |
--color-info | #60a5fa | --color-info-bg, --color-info-border |