Tokens and naming
Every value in your system has one name. The same name shows up in your CSS, your Tailwind classes, your Figma variables and what your AI agent reads.
Two layers
UIX keeps colors in two layers:
- Primitives are the raw scales, like
--color-primary-500. Each has a fixed value. - Semantic tokens say what a color is for, like
--bg-surfaceor--text-secondary. Each one points to a primitive, and the theme decides which one. In light mode--bg-surfacemay be white; in dark mode it is a dark neutral.
Build your UI with semantic tokens. Then dark mode, a new brand color or a contrast fix changes the whole UI without touching your components.
Color scales
Primary, secondary and neutral each get 11 steps, from 50 (lightest) to 950 (darkest). Error, warning and success get 5 steps: 50, 300, 500, 800 and 950. There is also a base white and black.
:root {
--color-base-white: #FFFFFF;
--color-base-black: #000000;
--color-primary-50: #EDF8F6;
--color-primary-100: #D8F0EB;
/* … 200 to 900 … */
--color-primary-950: #002E28;
--color-neutral-50: #F9FAFA;
/* … */
--color-error-50: #FFF3EE;
--color-error-300: #F6AC8F;
--color-error-500: #D04D00;
--color-error-800: #882F00;
--color-error-950: #451501;
}These values come from a teal system. Yours will differ.
Semantic colors
There are four groups. Each name becomes a CSS variable, like --bg-brand-hover or --text-on-brand.
| Group | Names |
|---|---|
bg | canvas, surface, subtle, muted, inverse, disabled, overlay; brand, brand-hover, brand-pressed, brand-subtle; secondary, secondary-hover, secondary-pressed, secondary-subtle; danger, danger-hover, danger-pressed, danger-subtle; warning, warning-subtle; success, success-subtle; info, info-subtle |
text | primary, secondary, tertiary, disabled, inverse, on-brand, on-secondary, on-danger, brand, danger, warning, success, info |
border | default, subtle, strong, brand, focus, danger, warning, success |
icon | primary, secondary, brand, on-brand, danger, warning, success |
The on- names are for text and icons on a filled color. text/on-brand is the label on a primary button.
Same name in every place
A token has one path, like bg/surface. Each place writes that path its own way.
| Token | CSS variable | Tailwind | Figma variable |
|---|---|---|---|
| bg/surface | --bg-surface | bg-surface | bg/surface |
| bg/brand | --bg-brand | bg-brand | bg/brand |
| text/primary | --text-primary | text-fg-primary | text/primary |
| text/secondary | --text-secondary | text-fg-secondary | text/secondary |
| border/default | --border-default | border-line-default | border/default |
| border/focus | --border-focus | border-line-focus | border/focus |
In Tailwind, text colors start with text-fg- and borders with border-line-. In Figma, the semantic colors live in the Theme collection, with one mode per theme. Your AI agent gets the full table in AGENTS.md.
Type
There are three font variables and one class per text style. Each style has its own size, line height and letter spacing variables.
--font-heading: 'Manrope', ui-sans-serif, system-ui, sans-serif;
--font-body: 'Manrope', ui-sans-serif, system-ui, sans-serif;
--font-mono: 'Roboto Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
--text-heading-1-size: 48px;
--text-heading-1-line-height: 1.2;
--text-heading-1-letter-spacing: -0.01em;
.text-heading-1 {
font-family: var(--font-heading);
font-weight: 700;
font-size: var(--text-heading-1-size);
line-height: var(--text-heading-1-line-height);
letter-spacing: var(--text-heading-1-letter-spacing);
}The styles are display (large and medium), heading 1 to 6, title, subtitle, body (xl to xs), label, caption, overline and code. Use the class, like text-heading-2 or text-body-medium, in plain CSS or as a Tailwind utility.
Spacing, corners and the rest
| Variables | Example values |
|---|---|
--space-* | --space-1 4px, --space-4 16px, up to --space-32 128px |
--radius-* | none, xs, sm, md, lg, xl, 2xl, 3xl, full |
--border-width-* | none, thin, medium, thick |
--size-icon-* | xs 12px, sm 16px, md 20px, lg 24px |
--shadow-* | xs, sm, md, lg, xl, 2xl, tinted by --shadow-color |
--opacity-* | 0, 5, 10, 20, 40, 60, 80, 100 |
--z-* | base, raised, dropdown, sticky, overlay, modal, popover, toast, tooltip |
--duration-* | instant, fast, normal, slow, slower |
--ease-* | standard, enter, exit, linear |
--breakpoint-* | sm 640px, md 768px, lg 1024px, xl 1280px, 2xl 1536px |
The values depend on your choices. The corners you pick, for example, change every radius.
Rules worth keeping
- Never hard-code colors, font sizes, spacing, radii, shadows or durations. Use the variables or Tailwind classes.
- Semantic over primitive:
bg-surfaceandtext-fg-primary, notblue-500or#2563eb. - No separate dark colors. The tokens switch with
data-theme. See Themes and dark mode. - Missing a value? Add a token instead of a one-off color, shadow or radius.