BrandTheme writes each token of the palette to a CSS variable on its own element. Components read only these variables, so you can nest themes, show two brands side by side, or switch at runtime.
Tokens
| Token | CSS variable | Used for |
|---|---|---|
surface | --bs-surface | Page background |
elevated | --bs-elevated | Cards, fields, popups |
ink | --bs-ink | Text |
muted | --bs-muted | Secondary text, field borders |
accent | --bs-accent | Primary actions, focus rings, highlights |
onAccent | --bs-on-accent | Text on the accent |
line | --bs-line | Dividers and outlines |
font | --bs-font | Body and UI type |
radius | --bs-radius | Corner radius |
voiceFont | --bs-voice-font | Optional second family for promise lines |
Two more are derived: --bs-accent-soft and --bs-line-soft, light tints for highlights and dividers.
Motion
Components time their movement with a few shared variables. Override any of them on a BrandTheme or a parent element to change the feel of a whole brand.
| CSS variable | Default | Used for |
|---|---|---|
--bs-ease-out | cubic-bezier(.2,.7,.2,1) | Things arriving: panels, slides, list items |
--bs-ease-in-out | cubic-bezier(.41,.19,.13,.95) | Things moving from one place to another |
--bs-ease-spring | cubic-bezier(.34,1.56,.64,1) | Things that answer a tap: menus, tabs, switches, cards |
--bs-duration-fast | 150ms | Fades on small popups |
--bs-duration | 420ms | Most movement |
--bs-duration-slow | 700ms | List entrances |
--bs-stagger | 60ms | Gap between list items entering one after another |
--bs-ease still works and points at --bs-ease-out. When the reader asks for reduced motion, every component shows at rest.
Modes
mode="light" and mode="dark" pin a mode. mode="system" follows the reader's setting through prefers-color-scheme.
Contrast
The Brand Studio contract check fails a palette when ink, muted text or text on the accent falls under 4.5:1 against its background. Run it before you ship a palette:
npm run check:brandYour own components
Read the same variables in your CSS and your components follow the brand too:
.promo {
background: var(--bs-elevated);
border: 1px solid var(--bs-line);
border-radius: var(--bs-radius);
color: var(--bs-ink);
}