Focused reference · Day 4 · Reviewed 2026-08-04

Variables & tokens

Primitive scales, semantic intent, aliases, and component bindings.

The production question

You're designing a new “info” badge for the dashboard, and the blue you want is pixel-identical to the one already used on the primary button. Do you bind the badge's fill to the existing action/primary token because the color matches today, or create a separate status/info token that happens to alias the same primitive? Get this wrong in one direction and a future primary-button color change silently recolors your info badges; get it wrong in the other direction and you've spawned a token that will never diverge from action/primary and just adds noise to the picker.

How to decide

  1. Ask what the value represents: a role (why it's used) or a scale step (what it literally is)? If it's a role, it needs a semantic variable — never bind a component straight to a primitive just because the color happens to look right today.
  2. Search the semantic collection for a token that already names this exact role before adding a new one. A second token that aliases the same primitive as an existing one is only justified if the two roles are likely to diverge later.
  3. Test for divergence directly: could this value ever need to change independently of the token it currently resembles? An info badge and a primary action button serve different jobs even when today's blue matches, so they earn separate tokens.
  4. If the value is a genuine one-off — a single decorative flourish with no repeated role — leave it as a documented raw exception instead of manufacturing a semantic name for something with no reuse.
  5. Alias the new semantic variable to a primitive, bind the component to the semantic variable rather than the primitive, then run the primitive-swap stress test: change the primitive and confirm only the intended tokens update downstream.

Correct vs. incorrect

Correct

The “Recovery failed” status badge and the destructive “Delete workload” button both currently render the same red. Instead of pointing both directly at red/600, the designer creates status/error (aliased to red/600) for the badge and action/destructive (also aliased to red/600 today) for the button. Weeks later, an accessibility pass needs the destructive button's red to get darker for contrast against white text, while the error badge's lighter tint already passes on its own background — because they're separate semantic tokens, only action/destructive gets repointed, and status/error is untouched.

Incorrect

A designer building the alert component notices blue/500 looks right for an informational icon and binds the icon fill directly to blue/500 instead of creating or reusing a status/info token. It ships fine. Two months later the brand's primary blue shifts from blue/500 to a new blue/600 during a rebrand, so every semantic alias gets repointed to the new value — except this icon, which was bound to the raw primitive rather than a token, so it silently keeps the old, now-orphaned blue while every token-bound surface around it updates.

Practice it, then try to break it

Open your Day 3 button and alert components. List every color and spacing value they currently use, and label each one “raw hex,” “bound to a primitive,” or “bound to a semantic token.” Create four semantic variables — action/primary, action/primary-hover, surface/alert, and text/on-alert — each aliased to an existing primitive, then rebind the components to consume only the semantic layer. Finally, change the primitive behind action/primary and confirm the button updates while an unrelated component, like a neutral summary card, does not.

Stress test: Re-alias surface/card from its neutral primitive to a saturated color primitive, as if testing a themed variant, then check every card-based component in the file — summary cards, alert cards, table row cards — for the first place text contrast breaks. A token layer that's genuinely semantic, not just a renamed primitive, lets you make this swap in one place and immediately see every real consumer, without hunting for a component that quietly kept a raw hex instead of the token.

Common mistakes

  • Binding a component directly to a primitive (blue/600) instead of a semantic token (action/primary), which defeats the entire reason for having an alias layer.
  • Naming a semantic token after its current appearance (blue-button, dark-gray-text) instead of its role (action/primary, text/secondary), so the name becomes false the moment the underlying color changes.
  • Building a large primitive scale — a dozen shades per hue — before any semantic layer exists, which produces options nobody has decided how to use rather than a working system.
  • Treating a finished token layer as a finished dark-mode solution, when the semantic layer is only the preparation; contrast and mode-switching still require deliberate follow-up work.

Accessibility and handoff

When a component's inspectable properties show a semantic variable name like action/primary instead of a raw hex or pixel value, developers can map it straight to a design-token file — a CSS custom property, a theme object — instead of eyeballing and hand-transcribing values, which is the difference between a later token change staying in sync with code and silently drifting the next time someone edits the palette in only one place.

FAQ

What's the actual difference between a variable and a style?
A style (text, effect, or paint style) bundles several properties under one reusable name and mainly serves visual consistency. A variable holds a single value, can be aliased to another variable, can switch per mode such as light or dark, and can bind directly to a component property like corner radius or an instance-swap slot — styles can't do either of those.
How many primitive shades do I actually need before starting on semantic tokens?
Fewer than you think. A working scale like neutral, blue, success, warning, and error with a handful of steps each is enough to start aliasing. Add a shade only when a real semantic need can't be satisfied by an existing step, not speculatively.
Is it ever okay to leave a value hard-coded instead of tokenizing it?
Yes. A genuine one-off decorative value with no reuse and no likely future divergence doesn't need a semantic name — document it as a deliberate exception rather than pretending every raw value is a system gap.
Do variables replace the variants from component work?
No, they solve different problems. Variants model a bounded set of component states or sizes, like primary/secondary or small/medium/large. Variables model a reusable value referenced across many components. A button's hierarchy variants typically each bind to a different action/* semantic color variable — the two systems compose, they don't substitute for each other.
Use the complete lesson

Take this skill into a connected project.

The full Mission 4 lesson includes guided steps, a timer, quiz, pass criteria, and saved progress.