Why tokens matter more than they used to
Tokens have always been the way to keep a design system consistent. What's changed is who's reading them. When you ask your coding agent to build a screen for you, it's supposed to read your components and your tokens to decide how and what to build. If the tokens are messy, or missing, the agent will invent values, and every invented value is a small piece of drift between your design and your product.
The three layers
The setup I keep coming back to has three layers, and each one has a different job:
- Primitive tokens: The raw palette and scales, like orange.500 or space.4. They describe what a value is, and they're never used directly in components.
- Semantic tokens: The values named by what they're for, like color.text.error or color.background.surface. Components use these, and this is the layer that makes themes and dark mode possible.
- Component tokens: Values specific to one component, like button.padding.horizontal. Only add these when a component genuinely needs its own value, otherwise this layer grows faster than anyone can maintain.
The thing is, a lot of teams stop at the first layer. They have a nice palette, and then components reach straight for orange.500. That works until the brand colour changes, or you need dark mode, and then you're searching the codebase by hand.
Name tokens by what they're for
The most useful rule I know is to name semantic tokens by what they're for. color.text.error tells a designer, a developer, and a coding agent exactly where it belongs. A name like red.600 only describes the colour, so people have to guess where it goes.
Good names are also human readable. If a new developer can read the token name out loud and know where it goes without opening the documentation, the name is doing its job.
How to create them, step by step
- Start from what's in production: Collect the colours, spacing, and type sizes the product actually uses today. You'll usually find far more values than the design file has.
- Merge the near-duplicates: Three almost identical greys become one. This is where you make design decisions, so do it with a designer and a developer in the same room.
- Build the primitive scale: Turn what's left into a palette and a spacing scale with consistent steps.
- Map semantic tokens onto it: Name each use, like surface, border, text, action, and error, and point it at a primitive.
- Set them up as Figma variables: Use modes for themes like light and dark, so designers work with the same names developers will use.
- Export them to the code: Generate CSS variables or your platform's equivalent from the same source, so Figma and the code can't drift apart.
What this looked like at Syndigo
At Syndigo, the product teams were working from a fragmented enterprise design system. Part of consolidating more than 70 components into one governed library was getting the values underneath them into a shape both the design file and the production code could share. That shared layer is what keeps a library and the code in step once the project is over.
Where to start
Open your codebase and count how many different colour values it uses. If the number is a lot bigger than your palette, that's your first job, and it's often smaller than teams expect.
Gideon Awolesi