Theming
Every color a component draws comes from a variable, and every variable belongs to a role. Redefine the variables and the whole catalogue moves with them.
Semantic roles
A component picks a role — brand, neutral, success, warning, danger — and the role resolves to a fill, the text on that fill, a border and a focus ring. That pairing is the convention: a component never names a color, only the part of a role it needs.
brand
Every variable a component reads when its `data-color` is `brand`.
| Token | What it controls | Components that read it |
|---|---|---|
--ui-brand-bg-tint | Tinted fill, for a quiet emphasis | Badge, Bubble, Button, DropZone, FileTrigger, LinkButton, Marker, Menu, Select, Sidebar, Table, TagGroup, Toast, Tree |
--ui-brand-bg-solid | Solid fill, for the loudest emphasis | Badge, Bubble, Button, Calendar, Checkbox, ColorSwatchPicker, ColorWheel, DropIndicator, FileTrigger, LinkButton, ListBox, Menu, Menubar, Meter, Pagination, ProgressBar, RadioGroup, RangeCalendar, Resizable, Select, Slider, Switch, TagGroup |
--ui-brand-fg | Text and icons in the tone | Badge, Button, FileTrigger, Link, LinkButton, NavLink, Sidebar, Spinner, Tabs, TagGroup, ToggleButton, Typeset |
--ui-brand-fg-muted | Secondary text, one step back from the body | Marker |
--ui-brand-fg-emphasis | The tone's strongest text | Bubble, ListBox, Marker, NavLink, RangeCalendar |
--ui-brand-fg-on-solid | Text drawn on the solid fill | Badge, Bubble, Button, Calendar, Checkbox, FileTrigger, LinkButton, ListBox, Menu, Menubar, Pagination, RadioGroup, RangeCalendar, Select, Switch, TagGroup |
--ui-brand-border | Ordinary border | Badge, Bubble, Button, FileTrigger, LinkButton, Marker, Toast, ToggleButton |
--ui-brand-border-strong | Border where the edge carries the emphasis | Badge |
--ui-brand-ring | Focus ring | Attachment, Button, Calendar, Carousel, Chart, Checkbox, ColorArea, ColorPicker, ColorSwatchPicker, ColorWheel, ComboBox, Command, Disclosure, DropZone, FileTrigger, GridList, ImagePlaceholder, Input, Link, LinkButton, Menu, Menubar, NavLink, NavigationMenu, NumberField, Pagination, RadioGroup, Resizable, ScrollArea, Select, Sidebar, Switch, Table, Tabs, TagGroup, TextArea, ToggleButton, Tree, Typeset |
--ui-brand-bg-tint-hover | Tinted fill while the pointer is over it | — |
--ui-brand-bg-tint-pressed | Tinted fill while it is held down | — |
--ui-brand-bg-solid-hover | Solid fill while the pointer is over it | — |
--ui-brand-bg-solid-pressed | Solid fill while it is held down | — |
--ui-brand-border-hover | The page's own surface, outside any tone | — |
neutral
Every variable a component reads when its `data-color` is `neutral`.
| Token | What it controls | Components that read it |
|---|---|---|
--ui-neutral-bg-tint | Tinted fill, for a quiet emphasis | Attachment, Badge, Bubble, Button, Calendar, Checkbox, ColorArea, ColorSlider, ColorSwatch, ColorWheel, Dialog, Disclosure, DropZone, FileTrigger, ImagePlaceholder, Input, Keyboard, LinkButton, Marker, Menubar, NumberField, OverlayArrow, RadioGroup, Resizable, Select, Sidebar, Table, Toast, Toolbar, Typeset |
--ui-neutral-bg-solid | Solid fill, for the loudest emphasis | Badge, Bubble, Button, Chart, Checkbox, FileTrigger, LinkButton, Meter, Tooltip |
--ui-neutral-fg | Text and icons in the tone | Accordion, Attachment, Badge, Breadcrumbs, Button, Calendar, Chart, ComboBox, DropZone, FileTrigger, ImagePlaceholder, Item, Keyboard, Link, LinkButton, Menubar, Meter, NavLink, NavigationMenu, NumberField, Pagination, ProgressBar, Sheet, Sidebar, Spinner, Table, Tabs, TagGroup, Text, Toast, ToggleButton, Typeset |
--ui-neutral-fg-muted | Secondary text, one step back from the body | AlertDialog, Attachment, Breadcrumbs, Calendar, Command, ContextMenu, Description, Dialog, GridList, Header, Input, Item, Marker, Message, Resizable, SearchField, Select, SentinelRow, Sidebar, Table, Tree, Typeset |
--ui-neutral-fg-emphasis | The tone's strongest text | AlertDialog, Attachment, Breadcrumbs, Bubble, Calendar, Command, Dialog, Disclosure, GridList, Heading, HoverCard, ImagePlaceholder, Input, Item, Label, ListBox, Marker, Menu, Menubar, Message, NavLink, NavigationMenu, NumberField, Pagination, RadioGroup, Select, Sidebar, Table, Tabs, Tree, Typeset |
--ui-neutral-fg-on-solid | Text drawn on the solid fill | Badge, Bubble, Button, Chart, Checkbox, FileTrigger, LinkButton, Tooltip |
--ui-neutral-border | Ordinary border | Attachment, Badge, Bubble, Button, Chart, ColorSlider, ColorSwatch, ColorWheel, FileTrigger, LinkButton, Marker, Meter, NumberField, ProgressBar, Resizable, ScrollArea, Select, Separator, Sidebar, Skeleton, Slider, Switch, Toast, ToggleButton, Toolbar, Typeset |
--ui-neutral-border-strong | Border where the edge carries the emphasis | Bubble, Checkbox, ImagePlaceholder, RadioGroup, Resizable, ScrollArea, Switch, Typeset |
--ui-neutral-ring | Focus ring | Button, Checkbox, FileTrigger, Link, LinkButton, Sidebar, TagGroup, TextArea, ToggleButton |
--ui-neutral-bg-tint-hover | Tinted fill while the pointer is over it | — |
--ui-neutral-bg-tint-pressed | Tinted fill while it is held down | — |
--ui-neutral-bg-solid-hover | Solid fill while the pointer is over it | — |
--ui-neutral-bg-solid-pressed | Solid fill while it is held down | — |
--ui-neutral-border-hover | The page's own surface, outside any tone | ColorPicker |
success
Every variable a component reads when its `data-color` is `success`.
| Token | What it controls | Components that read it |
|---|---|---|
--ui-success-bg-tint | Tinted fill, for a quiet emphasis | Badge, Button, FileTrigger, LinkButton, Marker, Sidebar, TagGroup, Toast |
--ui-success-bg-solid | Solid fill, for the loudest emphasis | Badge, Button, Checkbox, FileTrigger, LinkButton, Meter |
--ui-success-fg | Text and icons in the tone | Badge, Button, FileTrigger, Link, LinkButton, NavLink, Sidebar, Spinner, TagGroup, ToggleButton |
--ui-success-fg-muted | Secondary text, one step back from the body | Marker |
--ui-success-fg-emphasis | The tone's strongest text | Marker, NavLink |
--ui-success-fg-on-solid | Text drawn on the solid fill | Badge, Button, Checkbox, FileTrigger, LinkButton |
--ui-success-border | Ordinary border | Badge, Button, FileTrigger, LinkButton, Marker, Toast, ToggleButton |
--ui-success-border-strong | Border where the edge carries the emphasis | Badge |
--ui-success-ring | Focus ring | Button, Checkbox, FileTrigger, Input, Link, LinkButton, Select, Sidebar, TagGroup, TextArea, ToggleButton |
--ui-success-bg-tint-hover | Tinted fill while the pointer is over it | — |
--ui-success-bg-tint-pressed | Tinted fill while it is held down | — |
--ui-success-bg-solid-hover | Solid fill while the pointer is over it | — |
--ui-success-bg-solid-pressed | Solid fill while it is held down | — |
--ui-success-border-hover | The page's own surface, outside any tone | — |
warning
Every variable a component reads when its `data-color` is `warning`.
| Token | What it controls | Components that read it |
|---|---|---|
--ui-warning-bg-tint | Tinted fill, for a quiet emphasis | Badge, Button, FileTrigger, LinkButton, Marker, Sidebar, TagGroup, Toast |
--ui-warning-bg-solid | Solid fill, for the loudest emphasis | Badge, Button, Checkbox, FileTrigger, LinkButton, Meter |
--ui-warning-fg | Text and icons in the tone | Badge, Button, FileTrigger, Link, LinkButton, NavLink, Sidebar, Spinner, TagGroup, ToggleButton |
--ui-warning-fg-muted | Secondary text, one step back from the body | Marker |
--ui-warning-fg-emphasis | The tone's strongest text | Marker, NavLink |
--ui-warning-fg-on-solid | Text drawn on the solid fill | Badge, Button, Checkbox, FileTrigger, LinkButton |
--ui-warning-border | Ordinary border | Badge, Button, FileTrigger, LinkButton, Marker, Toast, ToggleButton |
--ui-warning-border-strong | Border where the edge carries the emphasis | Badge |
--ui-warning-ring | Focus ring | Button, Checkbox, FileTrigger, Input, Link, LinkButton, Select, Sidebar, TagGroup, TextArea, ToggleButton |
--ui-warning-bg-tint-hover | Tinted fill while the pointer is over it | — |
--ui-warning-bg-tint-pressed | Tinted fill while it is held down | — |
--ui-warning-bg-solid-hover | Solid fill while the pointer is over it | — |
--ui-warning-bg-solid-pressed | Solid fill while it is held down | — |
--ui-warning-border-hover | The page's own surface, outside any tone | — |
danger
Every variable a component reads when its `data-color` is `danger`.
| Token | What it controls | Components that read it |
|---|---|---|
--ui-danger-bg-tint | Tinted fill, for a quiet emphasis | Attachment, Badge, Button, FileTrigger, LinkButton, Marker, Menu, Sidebar, TagGroup, Toast |
--ui-danger-bg-solid | Solid fill, for the loudest emphasis | Badge, Bubble, Button, Calendar, Checkbox, FileTrigger, LinkButton, Meter |
--ui-danger-fg | Text and icons in the tone | Badge, Button, CheckboxGroup, FieldError, FileTrigger, Link, LinkButton, Menu, NavLink, NumberField, Sidebar, Spinner, TagGroup, ToggleButton |
--ui-danger-fg-muted | Secondary text, one step back from the body | Marker |
--ui-danger-fg-emphasis | The tone's strongest text | Attachment, Marker, NavLink |
--ui-danger-fg-on-solid | Text drawn on the solid fill | Badge, Bubble, Button, Calendar, Checkbox, FileTrigger, LinkButton |
--ui-danger-border | Ordinary border | Attachment, Badge, Button, FileTrigger, Input, LinkButton, Marker, Select, Toast, ToggleButton |
--ui-danger-border-strong | Border where the edge carries the emphasis | Badge |
--ui-danger-ring | Focus ring | Button, Checkbox, DatePicker, FileTrigger, Input, Link, LinkButton, Menu, Select, Sidebar, TagGroup, TextArea, ToggleButton |
--ui-danger-bg-tint-hover | Tinted fill while the pointer is over it | — |
--ui-danger-bg-tint-pressed | Tinted fill while it is held down | — |
--ui-danger-bg-solid-hover | Solid fill while the pointer is over it | — |
--ui-danger-bg-solid-pressed | Solid fill while it is held down | — |
--ui-danger-border-hover | The page's own surface, outside any tone | — |
surface
The page itself, which a tone sits on rather than replaces.
| Token | What it controls | Components that read it |
|---|---|---|
--ui-bg | Surface behind the tone's content | MessageScroller |
--ui-fg | Text and icons in the tone | — |
--ui-border | Ordinary border | — |
--ui-ring | Focus ring | — |
spacing
One step, multiplied by every spacing utility.
| Token | What it controls | Components that read it |
|---|---|---|
--ui-spacing | The step every spacing utility multiplies | Tree |
type scale
The named font sizes.
| Token | What it controls | Components that read it |
|---|---|---|
--ui-text-xs | Font size named xs | — |
--ui-text-sm | Font size named sm | — |
--ui-text-base | Font size named base | — |
--ui-text-lg | Font size named lg | — |
--ui-text-xl | Font size named xl | — |
--ui-text-2xl | Font size named 2xl | — |
--ui-text-3xl | Font size named 3xl | — |
--ui-text-4xl | Font size named 4xl | — |
--ui-text-5xl | Font size named 5xl | — |
--ui-text-6xl | Font size named 6xl | — |
--ui-text-7xl | Font size named 7xl | — |
--ui-text-8xl | Font size named 8xl | — |
--ui-text-9xl | Font size named 9xl | — |
font stacks
The three families, resolved to system faces.
| Token | What it controls | Components that read it |
|---|---|---|
--ui-font-sans | The sans family stack | — |
--ui-font-serif | The serif family stack | — |
--ui-font-mono | The mono family stack | — |
container scale
The named widths a container query compares against.
| Token | What it controls | Components that read it |
|---|---|---|
--ui-container-xs | Container width named xs | — |
--ui-container-sm | Container width named sm | — |
--ui-container-md | Container width named md | — |
--ui-container-lg | Container width named lg | — |
--ui-container-xl | Container width named xl | — |
--ui-container-2xl | Container width named 2xl | — |
chart
The categorical sequence a multi-series chart walks in order.
| Token | What it controls | Components that read it |
|---|---|---|
--ui-chart-1 | Series 1 of a chart | Chart |
--ui-chart-2 | Series 2 of a chart | — |
--ui-chart-3 | Series 3 of a chart | — |
--ui-chart-4 | Series 4 of a chart | — |
--ui-chart-5 | Series 5 of a chart | — |
--ui-chart-6 | Series 6 of a chart | — |
--ui-chart-7 | Series 7 of a chart | — |
--ui-chart-8 | Series 8 of a chart | Chart |
Light
What a document resolves to with no scheme class on it.
:root {
--ui-brand-bg-tint: var(--ui-color-brand-50);
--ui-brand-bg-solid: var(--ui-color-brand-600);
--ui-brand-fg: var(--ui-color-brand-600);
--ui-brand-fg-muted: var(--ui-color-brand-500);
--ui-brand-fg-emphasis: var(--ui-color-brand-900);
--ui-brand-fg-on-solid: white;
--ui-brand-border: var(--ui-color-brand-200);
--ui-brand-border-strong: var(--ui-color-brand-600);
--ui-brand-ring: var(--ui-color-brand-500);
--ui-neutral-bg-tint: var(--ui-color-neutral-50);
--ui-neutral-bg-solid: var(--ui-color-neutral-900);
--ui-neutral-fg: var(--ui-color-neutral-600);
--ui-neutral-fg-muted: var(--ui-color-neutral-500);
--ui-neutral-fg-emphasis: var(--ui-color-neutral-900);
--ui-neutral-fg-on-solid: white;
--ui-neutral-border: var(--ui-color-neutral-200);
--ui-neutral-border-strong: var(--ui-color-neutral-600);
--ui-neutral-ring: var(--ui-color-neutral-500);
--ui-success-bg-tint: var(--ui-color-success-50);
--ui-success-bg-solid: var(--ui-color-success-600);
--ui-success-fg: var(--ui-color-success-600);
--ui-success-fg-muted: var(--ui-color-success-500);
--ui-success-fg-emphasis: var(--ui-color-success-900);
--ui-success-fg-on-solid: white;
--ui-success-border: var(--ui-color-success-200);
--ui-success-border-strong: var(--ui-color-success-600);
--ui-success-ring: var(--ui-color-success-500);
--ui-warning-bg-tint: var(--ui-color-warning-50);
--ui-warning-bg-solid: var(--ui-color-warning-600);
--ui-warning-fg: var(--ui-color-warning-600);
--ui-warning-fg-muted: var(--ui-color-warning-500);
--ui-warning-fg-emphasis: var(--ui-color-warning-900);
--ui-warning-fg-on-solid: white;
--ui-warning-border: var(--ui-color-warning-200);
--ui-warning-border-strong: var(--ui-color-warning-600);
--ui-warning-ring: var(--ui-color-warning-500);
--ui-danger-bg-tint: var(--ui-color-danger-50);
--ui-danger-bg-solid: var(--ui-color-danger-600);
--ui-danger-fg: var(--ui-color-danger-600);
--ui-danger-fg-muted: var(--ui-color-danger-500);
--ui-danger-fg-emphasis: var(--ui-color-danger-900);
--ui-danger-fg-on-solid: white;
--ui-danger-border: var(--ui-color-danger-200);
--ui-danger-border-strong: var(--ui-color-danger-600);
--ui-danger-ring: var(--ui-color-danger-500);
--ui-bg: var(--ui-neutral-bg-tint, Canvas);
--ui-fg: var(--ui-neutral-fg-emphasis, CanvasText);
--ui-border: var(--ui-neutral-border, color-mix(in oklab, CanvasText 16%, transparent));
--ui-ring: var(--ui-brand-ring, Highlight);
--ui-spacing: 0.25rem;
--ui-container-xs: 20rem;
--ui-container-sm: 24rem;
--ui-container-md: 36rem;
--ui-container-lg: 48rem;
--ui-container-xl: 64rem;
--ui-container-2xl: 80rem;
--ui-font-sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
--ui-font-serif: ui-serif, Georgia, Cambria, "Times New Roman", serif;
--ui-font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
--ui-text-xs: 0.75rem;
--ui-text-sm: 0.875rem;
--ui-text-base: 1rem;
--ui-text-lg: 1.125rem;
--ui-text-xl: 1.25rem;
--ui-text-2xl: 1.5rem;
--ui-text-3xl: 1.875rem;
--ui-text-4xl: 2.25rem;
--ui-text-5xl: 3rem;
--ui-text-6xl: 3.75rem;
--ui-text-7xl: 4.5rem;
--ui-text-8xl: 6rem;
--ui-text-9xl: 8rem;
--ui-brand-bg-tint-hover: var(--ui-color-brand-100);
--ui-brand-bg-tint-pressed: var(--ui-color-brand-200);
--ui-brand-bg-solid-hover: var(--ui-color-brand-700);
--ui-brand-bg-solid-pressed: var(--ui-color-brand-800);
--ui-brand-border-hover: var(--ui-color-brand-300);
--ui-neutral-bg-tint-hover: var(--ui-color-neutral-100);
--ui-neutral-bg-tint-pressed: var(--ui-color-neutral-200);
--ui-neutral-bg-solid-hover: var(--ui-color-neutral-800);
--ui-neutral-bg-solid-pressed: var(--ui-color-neutral-700);
--ui-neutral-border-hover: var(--ui-color-neutral-300);
--ui-danger-bg-tint-hover: var(--ui-color-danger-100);
--ui-danger-bg-tint-pressed: var(--ui-color-danger-200);
--ui-danger-bg-solid-hover: var(--ui-color-danger-700);
--ui-danger-bg-solid-pressed: var(--ui-color-danger-800);
--ui-danger-border-hover: var(--ui-color-danger-300);
--ui-warning-bg-tint-hover: var(--ui-color-warning-100);
--ui-warning-bg-tint-pressed: var(--ui-color-warning-200);
--ui-warning-bg-solid-hover: var(--ui-color-warning-700);
--ui-warning-bg-solid-pressed: var(--ui-color-warning-800);
--ui-warning-border-hover: var(--ui-color-warning-300);
--ui-success-bg-tint-hover: var(--ui-color-success-100);
--ui-success-bg-tint-pressed: var(--ui-color-success-200);
--ui-success-bg-solid-hover: var(--ui-color-success-700);
--ui-success-bg-solid-pressed: var(--ui-color-success-800);
--ui-success-border-hover: var(--ui-color-success-300);
--ui-chart-1: var(--ui-color-brand-600);
--ui-chart-2: var(--ui-color-success-600);
--ui-chart-3: var(--ui-color-warning-600);
--ui-chart-4: var(--ui-color-danger-600);
--ui-chart-5: var(--ui-color-neutral-600);
--ui-chart-6: var(--ui-color-brand-400);
--ui-chart-7: var(--ui-color-success-400);
--ui-chart-8: var(--ui-color-warning-400);
}Dark
The same names, redefined under a dark ancestor. Add `.dark` to force it, or `.system` to follow the reader's own setting.
:is(.dark, .dark *) {
--ui-brand-bg-tint: var(--ui-color-brand-950);
--ui-brand-bg-solid: var(--ui-color-brand-600);
--ui-brand-fg: var(--ui-color-brand-400);
--ui-brand-fg-muted: var(--ui-color-brand-400);
--ui-brand-fg-emphasis: var(--ui-color-brand-100);
--ui-brand-border: var(--ui-color-brand-800);
--ui-brand-border-strong: var(--ui-color-brand-600);
--ui-neutral-bg-tint: var(--ui-color-neutral-950);
--ui-neutral-bg-solid: var(--ui-color-neutral-100);
--ui-neutral-fg: var(--ui-color-neutral-400);
--ui-neutral-fg-muted: var(--ui-color-neutral-400);
--ui-neutral-fg-emphasis: var(--ui-color-neutral-100);
--ui-neutral-fg-on-solid: var(--ui-color-neutral-900);
--ui-neutral-border: var(--ui-color-neutral-700);
--ui-neutral-border-strong: var(--ui-color-neutral-400);
--ui-success-bg-tint: var(--ui-color-success-950);
--ui-success-fg: var(--ui-color-success-400);
--ui-success-fg-muted: var(--ui-color-success-400);
--ui-success-fg-emphasis: var(--ui-color-success-100);
--ui-success-border: var(--ui-color-success-800);
--ui-success-border-strong: var(--ui-color-success-600);
--ui-warning-bg-tint: var(--ui-color-warning-950);
--ui-warning-fg: var(--ui-color-warning-400);
--ui-warning-fg-muted: var(--ui-color-warning-400);
--ui-warning-fg-emphasis: var(--ui-color-warning-100);
--ui-warning-border: var(--ui-color-warning-800);
--ui-warning-border-strong: var(--ui-color-warning-600);
--ui-danger-bg-tint: var(--ui-color-danger-950);
--ui-danger-fg: var(--ui-color-danger-400);
--ui-danger-fg-muted: var(--ui-color-danger-400);
--ui-danger-fg-emphasis: var(--ui-color-danger-100);
--ui-danger-border: var(--ui-color-danger-800);
--ui-danger-border-strong: var(--ui-color-danger-600);
--ui-brand-bg-tint-hover: var(--ui-color-brand-900);
--ui-brand-bg-tint-pressed: var(--ui-color-brand-800);
--ui-brand-bg-solid-hover: var(--ui-color-brand-700);
--ui-brand-bg-solid-pressed: var(--ui-color-brand-800);
--ui-brand-border-hover: var(--ui-color-brand-700);
--ui-neutral-bg-tint-hover: var(--ui-color-neutral-900);
--ui-neutral-bg-tint-pressed: var(--ui-color-neutral-800);
--ui-neutral-bg-solid-hover: var(--ui-color-neutral-200);
--ui-neutral-bg-solid-pressed: var(--ui-color-neutral-300);
--ui-neutral-border-hover: var(--ui-color-neutral-600);
--ui-danger-bg-tint-hover: var(--ui-color-danger-900);
--ui-danger-bg-tint-pressed: var(--ui-color-danger-800);
--ui-danger-bg-solid-hover: var(--ui-color-danger-700);
--ui-danger-bg-solid-pressed: var(--ui-color-danger-800);
--ui-danger-border-hover: var(--ui-color-danger-700);
--ui-warning-bg-tint-hover: var(--ui-color-warning-900);
--ui-warning-bg-tint-pressed: var(--ui-color-warning-800);
--ui-warning-bg-solid-hover: var(--ui-color-warning-700);
--ui-warning-bg-solid-pressed: var(--ui-color-warning-800);
--ui-warning-border-hover: var(--ui-color-warning-700);
--ui-success-bg-tint-hover: var(--ui-color-success-900);
--ui-success-bg-tint-pressed: var(--ui-color-success-800);
--ui-success-bg-solid-hover: var(--ui-color-success-700);
--ui-success-bg-solid-pressed: var(--ui-color-success-800);
--ui-success-border-hover: var(--ui-color-success-700);
--ui-chart-1: var(--ui-color-brand-400);
--ui-chart-2: var(--ui-color-success-400);
--ui-chart-3: var(--ui-color-warning-400);
--ui-chart-4: var(--ui-color-danger-400);
--ui-chart-5: var(--ui-color-neutral-400);
--ui-chart-6: var(--ui-color-brand-300);
--ui-chart-7: var(--ui-color-success-300);
--ui-chart-8: var(--ui-color-warning-300);
}