Foundations: thinking in design tokens
A primer for designers and engineers new to design tokens, with exercises.
Design tokens are not a file format. They are a way to give product decisions names.
That distinction matters because teams often start in the wrong place. They export a giant JSON file from Figma, wire it to CSS variables, and call the system done. The output exists, but nobody knows which token to use. Designers keep picking raw colors. Engineers keep adding local values. The token file grows, but the product does not get more coherent.
A useful token system starts with intent.
Start with the decision, not the value
The raw value #0f766e is not a design decision. It is a material. The decision is "primary action background" or "success text" or "focus ring." Those names tell the team why the value exists.
This is why I separate tokens into three layers:
- Primitives: raw materials like colors, spacing, font sizes, radii, and shadows.
- Semantic tokens: product intent like page background, muted text, strong border, primary action, and danger surface.
- Component tokens: local decisions for components that need state-specific values.
The primitive layer gives you control. The semantic layer gives you meaning. The component layer gives you precision when a reusable component has its own behavior.
Primitives should be boring
Primitives are not where the product language should live. They should be stable, predictable, and easy to replace.
Good primitive names are plain:
color.green.50
color.green.500
color.gray.900
space.4
radius.2
font.size.3
The primitive layer should not know that a green is used for a button or that a spacing value is used inside a card. Once primitives start describing intent, the system becomes harder to theme and harder to reason about.
Semantic tokens are the daily interface
Semantic tokens are the ones most designers and engineers should reach for:
color.bg.page
color.bg.surface
color.text.primary
color.text.muted
color.border.default
color.action.primary.bg
color.action.primary.text
These names survive redesigns because they describe jobs, not appearances. If the brand changes from green to blue, color.action.primary.bg can change while the product code remains meaningful.
The test is simple: can a new designer understand which token to use without knowing the color palette by heart? If yes, the semantic layer is working.
Component tokens should be used sparingly
Component tokens are useful when a component has real local behavior: a button with pressed states, an input with validation states, a tooltip with elevation rules.
The danger is turning every component into its own isolated theme. If every card, list, panel, and button has a full set of local tokens, you have not built a system. You have built many tiny systems.
The healthiest pattern is for component tokens to point back to semantic tokens.
button.primary.bg = color.action.primary.bg
button.primary.text = color.action.primary.text
input.focus.ring = color.focus.ring
card.border = color.border.default
This keeps components flexible without breaking the shared language.
Modes are product contexts
Light and dark mode are obvious examples, but modes can also represent density, brand, accessibility, or enterprise requirements. The key is that a mode should represent a real product context, not a visual novelty.
If the product needs high contrast, create a high-contrast mode. If the product has multiple brands with different palettes, create brand modes. If a marketing page wants a seasonal theme once a year, that probably does not belong in the core token system.
Modes become expensive because every semantic token needs an answer in every mode. Add them only when the product need is durable.
Handoff is the real test
A token system is working when handoff becomes less interpretive. A designer can inspect a Figma component, see color.action.primary.bg, and an engineer can map it to the same CSS variable without asking what green to use.
The Figma variable explains the role, not only the color.
The CSS variable carries the same name into implementation.
One-off values stand out because the system language is clear.
Exercises for a team
If you are introducing tokens to a team, do not start with a lecture about architecture. Start with a screen everyone knows. Take one card, form, or settings panel and ask the team to name every repeated decision in it: page background, elevated surface, default text, muted text, border, primary action, danger action, spacing, radius, and focus state.
Then separate the list into primitive, semantic, and component decisions. The discussion will expose where the team is mixing layers. Designers may be using raw color values for semantic jobs. Engineers may be creating component-specific CSS variables because no semantic token exists. Product managers may discover that "make it more prominent" has no shared implementation language.
The exercise works because it connects tokens to a product surface instead of a theoretical system.
Common failure modes
The first failure mode is over-tokenizing. Not every value needs a name on day one. If the system has more tokens than decisions, the team will stop trusting it.
The second failure mode is under-documenting. A token name can explain intent, but it cannot explain every usage rule. If color.text.muted should not be used for disabled text, say that somewhere.
The third failure mode is treating tokens as design-only. Tokens become powerful when they cross the boundary into code, QA, documentation, and review. If the names exist only in Figma, the system has not finished traveling.
The goal is not to remove judgment. The goal is to make routine decisions obvious so the team can spend judgment where it matters.