Guide · · 7 min read
Design Tokens Explained: From Moodboard to Code
Design tokens explained: color, type, spacing, radius and shadow tokens, primitive vs semantic naming, and how a moodboard becomes CSS and a Tailwind theme.

Design tokens are named values for every visual decision in a design: colors, fonts, type sizes, spacing, corner radius, shadows. Instead of writing #1a1a1a or 24px in a hundred places, you write color-text-primary or space-5 once, and every design file and stylesheet refers to that name. Tokens are how a design direction, often born on a moodboard, travels into code intact, and how it stays consistent when the site grows, gets a dark mode, or gets a rebrand.
Key takeaways
- A token is a name plus a value, and the name is the important part.
- Use two layers: primitive tokens for raw values and semantic tokens for purposes. Components use the semantic layer.
- The core token families are color, typography, spacing, radius and shadow; motion and breakpoints often follow.
- On the web, tokens usually end up as CSS custom properties, and in Tailwind v4 as an
@themeblock. - A good moodboard already contains most of your tokens; the work is naming them and assigning roles.
What a design token actually is
At its simplest, a token is a key and a value: color-brand is #ff5a1f. That sounds like a variable, and in code it usually becomes one. What makes it a token is that it is shared: the same name exists in the design tool, in the code, in the documentation, and in any export you hand to another platform.
That shared name changes how teams talk. A designer no longer says "make that slightly darker grey"; they say "that should be text-subtle, not text-primary". A developer no longer guesses which of four similar greys a mockup meant. And when the brand orange changes, it changes in one place.
The token families
Color tokens
Color is usually the biggest family. It typically covers:
- Brand colors: the primary accent and perhaps one or two supporting hues.
- Neutrals: a ramp of greys (or warm or cool off-greys) for text, borders and surfaces.
- Feedback colors: success, warning, error, info.
- Roles: background, surface, raised surface, text, subtle text, border, focus ring.
Most systems generate a ramp for each hue, from very light to very dark, often numbered from 50 to 950 in steps of 50 or 100. If you are still choosing the colors themselves, the website color palette guide covers that part.
Typography tokens
Type tokens cover font families (display, body, mono), font weights, and a set of sizes from your type scale, each ideally paired with a line height and letter spacing. Some systems bundle these into composite tokens like text-heading-2 that carry size, line height, weight and tracking together. The type scale guide explains how to choose the sizes.
Spacing tokens
A short scale of distances, usually on a 4px or 8px grid: 4, 8, 12, 16, 24, 32, 48, 64, 96, 128. These drive padding, margins and gaps. See the spacing system guide for a full sample scale.
Radius tokens
Corner radius is a small number with a large effect on mood. A system might define radius-none (0), radius-sm (4px), radius-card (8px or 12px), radius-panel (16px) and radius-pill (a very large value like 9999px, which turns any button into a pill). Sharp corners read as precise or editorial; soft ones read as friendly.
Shadow tokens
Shadows are best treated as elevation levels rather than one-off effects: shadow-sm for a resting card, shadow-md for a dropdown, shadow-lg for a dialog. Each token holds the full shadow definition (offsets, blur, spread, color). Keeping to three or four levels stops every component inventing its own.
And the rest
Many systems also tokenize motion (durations and easing curves), breakpoints, z-index layers and opacity. Start with the five families above; add the others when you notice the same value repeated.
Naming: primitive versus semantic tokens
The most useful idea in token design is splitting tokens into layers.
Primitive tokens (sometimes called global or core tokens) name raw values without saying what they are for: blue-500, grey-900, space-4, radius-2. They are your palette and your scales.
Semantic tokens (sometimes called alias tokens) name a purpose and point at a primitive: color-text-primary is grey-900, color-action is blue-500, color-surface-raised is grey-50.
Some larger systems add a third, component layer: button-primary-background points at color-action.
| Layer | Example name | Example value | Who uses it |
|---|---|---|---|
| Primitive | grey-900 | #18181b | Only other tokens |
| Primitive | orange-500 | #ff5a1f | Only other tokens |
| Semantic | color-text-primary | {grey-900} | Components, layouts |
| Semantic | color-brand | {orange-500} | Components, layouts |
| Component | button-primary-bg | {color-text-primary} | One component |
The rule that makes this work: components only use semantic (or component) tokens, never primitives. That is what makes dark mode easy: you remap color-text-primary from grey-900 to grey-50 and every component follows, without touching a single component.
A few naming habits help:
- Name by purpose, not appearance.
color-dangersurvives a palette change;color-redbecomes a lie the day danger turns orange. - Use a consistent order, such as category, then property, then variant, then state:
color-text-subtle,color-border-focus. - Keep names boring. Clever names are hard to guess, and guessability is the whole point.
The W3C Design Tokens format
Tokens are most useful when tools can exchange them. The W3C Design Tokens Community Group has developed a shared JSON format for exactly that, and a growing number of design tools and build tools can read or write it.
In general terms, the format works like this:
- Each token is an object with a
$valueand usually a$type, such as color, dimension, fontFamily, fontWeight, duration or shadow. An optional$descriptiondocuments it. - Tokens are organized in nested groups, so a token's name is its path:
color.text.primary. - One token can reference another by wrapping its path in curly braces, for example a
$valueof{color.grey.900}. That is how semantic tokens point at primitives. - Composite types, like typography or shadow, hold several values in one token.
You do not have to author tokens in this format by hand. It is mainly an exchange format: a source of truth that a build step turns into CSS variables, Tailwind config, iOS or Android values, or whatever each platform needs.
Tokens as CSS custom properties
On the web, tokens almost always end up as CSS custom properties, declared once on :root and used everywhere with var(). For example, --color-text-primary: #18181b; on :root, then color: var(--color-text-primary); in a component.
Custom properties are a natural fit because they cascade. Redefine --color-text-primary inside a dark-mode media query, or on an element with data-theme="dark", and every component inside picks up the new value at runtime. No rebuild, no duplicated stylesheets.
Tokens in a Tailwind v4 theme
Tailwind CSS v4 moved its configuration into CSS. You declare tokens inside an @theme block, and Tailwind turns them into both CSS variables and utility classes.
A few lines show the idea:
--color-brand: #ff5a1f;creates utilities likebg-brand,text-brandandborder-brand.--font-display: "Inter", sans-serif;createsfont-display.--radius-card: 8px;createsrounded-card.--shadow-raised: 0 1px 2px rgb(0 0 0 / 0.06);createsshadow-raised.--spacing: 0.25rem;sets the base unit, sop-4becomes 16px andgap-6becomes 24px.
The prefix of each variable (its namespace) decides which utilities it generates: --color-* for colors, --font-* for families, --text-* for sizes, --radius-* for corners, --shadow-* for shadows, and so on. Because the variables are real CSS custom properties, the rest of your CSS can use them too.
Component libraries add their own semantic layer on top. shadcn/ui, for example, expects variables such as --background, --foreground, --primary, --muted, --border, --ring and --radius. Mapping your semantic tokens onto those names is how a component library arrives already looking like your brand.
From moodboard to tokens
A design direction usually starts loose: a moodboard of references, a feeling, a few colors that keep coming up. Turning that into tokens is mostly a matter of extracting decisions that are already there and giving them names and roles.
- Pull the palette. Pick the four to eight colors that define the direction. Build a ramp for the accent and a neutral ramp. These are your primitives.
- Assign roles. Decide which neutral is the page background, which is text, which is subtle text, which is a border, and which color is the action color. These are your semantic tokens. Check text contrast as you assign them.
- Fix the type. Choose a display and a body family, set a base size and a ratio, and name each step of the scale.
- Set the spacing scale and density. Generous spacing for a calm direction, tighter for a dense one.
- Decide the shape. Radius and shadow tokens carry a surprising amount of mood: pill buttons and soft shadows feel friendly; square corners and hairline borders feel exact.
- Export. Write the tokens to CSS variables, a Tailwind
@theme, and whatever else your tools need.
This is also how MUUDS moodboards are put together: each design direction comes with a palette, fonts, a type scale and spacing already decided, and exports as DESIGN.md, design tokens, a Tailwind theme, a shadcn theme, Framer styles or an AI prompt. If you prefer to build your own, the guide to making a website moodboard covers the earlier, looser stage.
Common mistakes
- Tokenizing too early. Wait until a value repeats or a decision is clear. A token for every pixel is just a slower stylesheet.
- Only primitives. Without a semantic layer, dark mode and rebrands mean editing every component.
- Names that describe values.
color-light-bluebreaks the day it stops being light blue. - Two sources of truth. If the design tool and the code each define tokens separately, they will drift. Pick one source and generate the other.
In short
Design tokens are the shared names for your visual decisions. Keep primitives for raw values, semantic tokens for purposes, and let components use only the semantic layer. Store them in a format tools can exchange, ship them as CSS custom properties or a Tailwind @theme, and treat your moodboard as the first draft of your token file.
Questions, answered
What are design tokens?
Design tokens are named values for the decisions in a visual design, such as colors, font sizes, spacing, corner radius and shadows. Instead of writing a hex code or pixel value directly, designers and developers use the token's name, so one change updates every place it appears.
What is the difference between primitive and semantic tokens?
Primitive tokens name raw values, like blue-500 or space-4. Semantic tokens name a purpose, like color-text-primary or color-surface-raised, and point at a primitive. Components should use semantic tokens so a theme can change without editing them.
What is the W3C design tokens format?
It is a JSON format developed by the W3C Design Tokens Community Group for exchanging tokens between tools. Each token has a $value and usually a $type, tokens can be grouped, and one token can reference another by name in curly braces.
How do design tokens work with Tailwind CSS v4?
Tailwind v4 reads tokens from an @theme block of CSS custom properties. A variable such as --color-brand creates utilities like bg-brand and text-brand, and the same variables are available to any other CSS on the page.
design tokensdesign systemstailwind


