A brand palette gives you colors. A product interface needs decisions.
Which color belongs behind a primary action? Which text color works on that background? What changes when the same component appears on a dark surface?
A swatch called “Brand Green” cannot answer all of those questions.
Semantic design tokens give visual values names based on their purpose. Instead of asking every designer and developer to choose the right green, the system defines what a primary action uses.
That makes the relationship between brand and interface explicit. It also gives you a place to change that relationship without editing each component separately.
Separate the palette from its purpose
Consider a hypothetical brand with a bright green accent.
The marketing website uses it in large headlines and decorative shapes. The product team also wants it on buttons, links and success messages.
Those uses have different requirements. A color that works as a decorative accent may be unsuitable for small text on white. Sharing a color also does not mean sharing a meaning: “Continue” and “Payment received” serve different purposes.
A practical token structure separates three decisions:
| Layer | Question it answers | Example |
|---|---|---|
| Palette | Which visual values are available? | color.green.700 |
| Semantic | What purpose does this value serve? | color.action.primary.background |
| Component, when needed | What does this specific component use? | button.primary.background |
This three-layer structure is an implementation recommendation, not a universal requirement. A small interface may work well with palette and semantic tokens alone.
Carbon provides a concrete example of role-based color tokens. Its themes assign values to roles while keeping token names consistent across themes.
The useful distinction is between a value and the reason you chose it.
Name tokens after decisions that should survive change
green-button describes an appearance and an element.
action-primary-background describes a role.
If the brand changes from green to blue, the second name still makes sense. If the same action appears in a different theme, its role can remain stable while its value changes.
Start with a small vocabulary:
- Surface: page, raised panel, overlay
- Text: primary, secondary, inverse
- Border: default, strong
- Action: primary, secondary, destructive
- Feedback: success, warning, error
Then define what each term means.
“Secondary text” might cover supporting descriptions. It should not automatically cover disabled labels, placeholders and every piece of small text. Those cases may have different behavior and constraints.
Avoid creating a token because two elements happen to share a hex value today. Create a shared token when they should change together.
A success label and a primary button might both be green. Keeping their semantic roles separate lets one change without forcing the other to follow.
Make foreground and background decisions together
A background token is incomplete without knowing what appears on it.
For a primary action, define at least the background and foreground relationship:
:root {
--palette-green-700: #006b57;
--action-primary-background: var(--palette-green-700);
--action-primary-foreground: #ffffff;
}
.button-primary {
background: var(--action-primary-background);
color: var(--action-primary-foreground);
}
This is an illustrative CSS mapping, not a complete button implementation.
The component still needs appropriate hover, active, focus and disabled behavior. Those decisions belong in the system too, even when some are expressed through component styles rather than separate tokens.
Check the actual foreground and background combinations. A token name containing “accessible” proves nothing.
WCAG 2.2’s minimum text contrast criterion generally requires 4.5:1 for ordinary text and 3:1 for qualifying large text, with specified exceptions. Brand guidelines do not exempt ordinary interface text from that requirement. These ratios address text contrast, not complete accessibility conformance.
If the bright brand accent fails for a button label, define a suitable action color. The original accent can still serve other visual roles.
Keep theme changes at the semantic boundary
Dark mode exposes weak token naming quickly.
A token called text-black becomes awkward when text needs to be light. A token called text-primary can keep its meaning.
For example:
:root {
--surface-page: #ffffff;
--text-primary: #171717;
}
[data-theme="dark"] {
--surface-page: #171717;
--text-primary: #f5f5f5;
}
.page {
background: var(--surface-page);
color: var(--text-primary);
}
The component consumes the role. The theme supplies its value.
Do not treat dark mode as an automatic inversion. Review surfaces, borders, selected states and feedback colors in context. A palette transformation cannot decide whether a warning remains noticeable or a raised panel remains distinct.
My recommendation is to validate a few representative screens before expanding a theme across the product. Use a dense table, a form, an overlay and a screen with several status messages. They expose different relationships.
Add component tokens when they create useful independence
Component tokens can provide a deliberate boundary:
:root {
--button-primary-background:
var(--action-primary-background);
}
That boundary is useful if buttons need to evolve independently from other primary actions.
It adds little value when every component token simply forwards another token forever, with no ownership or variation requirement.
Before adding one, ask what should be allowed to change independently.
For a small website, a semantic action token may be sufficient. For a product with several button variants, multiple brands and a maintained component library, the extra layer may be justified.
The goal is a manageable set of decisions. Token count is not a measure of system quality.
Choose a source of truth that reaches production
A design file and a codebase can each contain a perfect token library while disagreeing with each other.
Decide where token changes originate, how they reach other tools and who checks the result.
The Design Tokens Community Group’s stable 2025.10 Format Module defines a JSON interchange format, including typed values and references between tokens. That provides a shared representation for supporting tools. It does not establish that every design tool or build pipeline supports the format correctly.
Before adopting a pipeline, test a small round trip:
- Define a palette value.
- Reference it through a semantic token.
- Export it to the target platform.
- Use the output in a real component.
- Change the source value and confirm the component updates.
Inspect the generated output. Check whether references, descriptions and theme mappings survive the tools involved.
A successful export is only one part of the workflow. The component must actually consume it.
Migrate one complete pattern first
Replacing every hex code in a repository can create a large diff without establishing a coherent system.
Start with a repeated pattern, such as primary actions.
Identify its current appearances, define the intended roles and migrate the relevant components. Include its states and theme variations.
Keep a simple mapping:
| Existing usage | Intended role | Migration decision |
|---|---|---|
| Green purchase button | Primary action | Use primary action tokens |
| Green confirmation message | Success feedback | Keep a separate success role |
| Green decorative shape | Brand expression | Use a palette or brand token |
| Green inline link | Navigation | Define and verify a link role |
The values may overlap. The responsibilities remain distinct.
Review representative pages after migration. Look for components that still override the system, unexpected inheritance and states that disappeared during cleanup.
Expand only after that first pattern works in design and code.
Document the rule behind the name
A token reference should explain when to use a role, where it should not appear and which other roles it pairs with.
For example:
Primary action background: Use for the main action in a defined task area. Pair with primary action foreground. Do not use it to communicate success status.
That guidance helps the next person make the same decision without reconstructing the original discussion.
Ownership matters too. Someone needs to review new roles, resolve duplicates and manage changes to existing names.
A useful token system lets a team answer three questions:
What does this value mean? Where is it used? What should change with it?
If the names and mappings cannot answer those questions, adding more tokens will only give the ambiguity more places to live.
Conversation
Discussion
Loading comments…