Article
Design tokens that survive the handoff
Naming, scaling and shipping tokens so Figma and code never drift apart, even two years in.
Every design system I’ve inherited started with good intentions and a tidy Figma library. Two years later, the site had forty greys, three “primary” blues and a spacing value called margin-weird. Nobody broke it on purpose. It drifted, one handoff at a time.
Tokens are supposed to stop that drift. Most of the time they don’t — not because the idea is wrong, but because the tokens were designed for the day they were created, not for the people who inherit them. Here is how I build tokens now, across agency projects in Figma, WordPress builds and bespoke front ends.
A token is a decision, not a value
#f2b705 is a value. --color-primary is a decision: this is the colour we use for emphasis. The value can change; the decision should survive.
That’s why I organise tokens in three tiers:
- Primitives — the raw palette and scales:
yellow-500,space-24,font-size-16. No meaning, just options. - Semantic tokens — decisions:
color-primary,color-text-muted,space-section,text-body. This is the layer designers and developers talk in. - Component tokens (only when needed) —
button-padding-inline,chat-bubble-radius. They point at semantic tokens, never at raw values.
Components only ever use tiers two and three. When the brand yellow changes, one semantic token moves and the whole system follows.
Name for the reader two years from now
Names are the part of a token system that survives longest, so they get the most care:
- Say what it’s for, not what it looks like.
color-danger, notcolor-red. The day “danger” becomes orange, the name is still true. - One naming pattern, everywhere. Category, then role, then variant:
color-text-muted,color-border-strong,space-block-lg. - Numbers for scales, words for roles.
space-16,space-24,space-48are a scale;space-sectionis a decision that uses it. - No “new”, “v2” or “final”. They are dates in disguise, and they age badly.
Scales that behave
A good scale makes the right choice the easy one. My spacing scale is small, and fluid where it matters:
--space-16: 16px;
--space-24: 24px;
--space-48: clamp(32px, 3.333vw, 48px);
--space-96: clamp(24px, 6.667vw, 96px);
--space-128: clamp(48px, 8.889vw, 128px);
Each fluid step reaches its full size at a 1440px viewport and shrinks gracefully below it, so designers can spec one value and trust it on every screen. Type works the same way: a handful of sizes, each defined once, stepping down together at the same breakpoints.
Write the reason next to the value
The single habit that saves the most arguments: every token that encodes a rule carries the rule in a comment.
--color-primary: #f2b705; // 10.4:1 on --color-dark — AAA for text at any size
--color-overlay: rgb(255 255 255 / 10%); // Decorative surface only, not a contrast boundary
--text-label: 14px; // Cropaso is wide and all caps: labels start at 14px
When someone new wants to “just lighten the muted text a bit”, the comment tells them what they’d be breaking. It turns tokens from a list into documentation.
One source of truth, two outputs
Drift happens when Figma and code are two sources of truth. Pick one direction and automate it:
- Figma variables hold primitives and semantic tokens, with modes for themes.
- They export to JSON (Tokens Studio or Figma’s own export), which lives in the repository.
- A build step (Style Dictionary, or a small script) turns that JSON into CSS custom properties — and, when the project needs it, into Elementor global colours or a PHP config.
On smaller projects I skip the pipeline and keep the SCSS token file as the source of truth, with Figma variables mirroring it by name. What matters isn’t the tooling; it’s that everyone knows which side wins.
If a value isn’t a token, it’s a bug waiting to be copied.
Plan for change
Tokens that survive are tokens that can change without fear:
- Deprecate, don’t delete. Keep the old name pointing at the new token for a release, with a comment saying when it goes.
- Changelog every token change, however small. “Muted text from 70% to 80% white for contrast” is a line that saves a future debate.
- Lint for raw values. A stylelint rule that flags hex codes and pixel values outside the token files keeps new code honest.
The handoff checklist
Before I hand a project over to an agency team or a client’s developers, I check:
- Every colour, size and space in components comes from a token.
- Semantic names describe roles, not appearances.
- Rules (contrast, minimum sizes) are written next to the values that encode them.
- There is one source of truth, and the README says which.
- Figma variable names match the code, character for character.
None of this is glamorous. But two years in, when someone opens the token file for the first time, it reads like a set of decisions they can trust — and that is what keeps a design system from drifting apart.