Tokens

Colours, type and spacing as theme tokens.

Tokens are the design decisions of a file: colours, fonts, radii and other values that repeat. They are Tailwind v4 theme variables in the @theme block of the style element. Each token makes classes: --color-accent makes bg-accent, text-accent, border-accent and more.

@theme {
  --font-sans: 'Inter', ui-sans-serif, system-ui, sans-serif;
  --font-display: 'Inter', ui-sans-serif, system-ui, sans-serif;
  --color-background: #f8fafc;
  --color-foreground: #0f172a;
  --color-accent: #2563eb;
  --color-accent-foreground: #ffffff;
  --radius-lg: 12px;
}

Names

The first part of the name sets the classes that the token makes:

Name Classes Example
--color-* bg-*, text-*, border-*, ring-*, fill-*, stroke-*, outline-*, from-*, to-* --color-accent gives bg-accent
--font-* font-* (family) --font-display gives font-display
--text-* text-* (size) --text-display: 72px gives text-display
--font-weight-* font-* (weight) --font-weight-heavy: 850
--leading-* leading-* --leading-display: 1.05
--tracking-* tracking-* --tracking-display: -0.03em
--radius-* rounded-* --radius-lg: 12px gives rounded-lg
--shadow-* shadow-* --shadow-card: 0 1px 2px rgb(0 0 0 / 0.06)
--spacing-* p-*, m-*, gap-*, w-*, h-* --spacing-gutter: 24px gives px-gutter
--container-* @*: container variants and max-w-* --container-8xl: 96rem
  • A type scale is a set of --text-* tokens: --text-body: 10pt gives text-body, and --text-caption: 8pt gives text-caption. A value can use any unit (px, rem, pt). Do not write --font-size-*: Tailwind does not read it, so SetTokens changes it to --text-*.
  • A size token can carry its line height, letter spacing and weight: --text-display--line-height: 1.05, --text-display--letter-spacing: -0.03em, --text-display--font-weight: 700.
  • Do not change --spacing. It is the base step of all spacing classes.
  • Do not add --breakpoint-* tokens. Viewport variants do not work in frames.

The standard tokens

GetStyle writes these tokens, and the examples in this skill use them. Use the same names in a new design, so that styles and examples fit.

Token Class Use
--color-background bg-background The page behind everything
--color-foreground text-foreground Main text on the background and on surfaces
--color-surface bg-surface Cards, panels, inputs, sidebars
--color-muted bg-muted Subtle fills: chips, table heads, image placeholders
--color-muted-foreground text-muted-foreground Secondary text: captions, labels, hints
--color-border border-border, ring-border, divide-border Hairlines and dividers
--color-accent bg-accent, text-accent Main actions, links, the selected state
--color-accent-foreground text-accent-foreground Text and icons on the accent colour
--font-sans none The default font of all text
--font-display font-display Headings
--font-mono font-mono Code, numbers in tables, small labels
--radius-sm to --radius-xl rounded-sm to rounded-xl Radii from small controls to large cards

--font-sans is the default font of all text, also when the font is a serif. Put the body font in it.

Add other tokens when a design needs them:

  • Status colours: --color-danger, --color-success and --color-warning, each with a -foreground token.
  • Brand colours: --color-brand-1, --color-brand-2.
  • Display type: --text-display with its line height and letter spacing.

Colour pairs

A background token and a text token make a pair. Use them together, so that the text has enough contrast in each mode:

Background Text on it
bg-background text-foreground, text-muted-foreground
bg-surface text-foreground, text-muted-foreground
bg-muted text-foreground, text-muted-foreground
bg-accent text-accent-foreground
bg-danger text-danger-foreground

Keep the contrast of text at 4.5:1 or more, and of large text and icons at 3:1 or more.

When to use a token

  • Use a token for each colour, font and radius that the design uses more than one time.
  • Use a token when the user chose one. Knighn writes a token class only when the value is a token that someone chose.
  • A colour that shows only one time, such as the colour of one illustration, can stay literal: bg-[#ffd23f].
  • Do not copy the value of a token into a class. Write bg-accent, not bg-[#2563eb].

Modes

A mode set is a data attribute that changes tokens. The base values are in @theme. A mode block changes some of them:

@theme {
  --color-background: #ffffff;
  --color-foreground: #0a0a0a;
  --color-surface: #f5f5f5;
}
[data-theme='dark'] {
  --color-background: #0a0a0a;
  --color-foreground: #fafafa;
  --color-surface: #1c1c1e;
}
[data-brand='rose'] {
  --color-accent: #e11d48;
}
  • The theme set has the modes of light and dark. The base values are the light mode.
  • Other sets use their own attribute, such as data-brand or data-density.
  • In a mode block, change only the tokens that are different in that mode.
  • A frame takes a mode with modes: { theme: 'dark' } on its canvas item. An element takes a mode with data-theme="dark".
  • Tokens change with the mode. Literal colours do not change.

Write mode blocks with SetTokens:

SetTokens({ '--color-background': '#0a0a0a', '--color-foreground': '#fafafa' }, { mode: 'dark' })
SetTokens({ '--color-accent': '#e11d48' }, { mode: { brand: 'rose' } })

Aliases in mode blocks

A token can refer to another token: --color-ring: var(--color-accent). The browser resolves the reference where the token is declared, which is the root. So when a mode block changes --color-accent, --color-ring keeps the old colour.

Declare the alias again in each mode block that changes its source:

@theme {
  --color-accent: #2563eb;
  --color-ring: var(--color-accent);
}
[data-theme='dark'] {
  --color-accent: #60a5fa;
  --color-ring: var(--color-accent);
}

Read and write tokens

  • GetTokens() returns { tokens, modes }. Read it before you add tokens, and do not overwrite tokens that the design uses.
  • SetTokens(map, { mode }) merges tokens into the @theme block or into a mode block. A value of null removes a token.
  • ImportTokens(css) reads the tokens of a project's CSS (the text of a globals.css) through SetTokens: the custom properties of :root, html and @theme become base tokens, and those of .dark, [data-theme="dark"] and @media (prefers-color-scheme: dark) become the dark mode. Each var() is resolved in each mode, so --color-background: var(--background) gets the light and the dark value. It returns { tokens, dark }.
  • GetStyle(name) returns a full set of standard tokens for a style, with its dark mode.
const { tokens } = GetTokens()
if (!tokens['--color-danger']) {
  SetTokens({ '--color-danger': '#dc2626', '--color-danger-foreground': '#ffffff' })
  SetTokens(
    { '--color-danger': '#f87171', '--color-danger-foreground': '#1f0a0a' },
    { mode: 'dark' }
  )
}