Design Tokens
Design Tokens
Definition: Named, reusable values, a specific blue, a specific spacing unit, that represent a single design decision once, then get consumed consistently across design tools and code instead of being hardcoded repeatedly.
How It Works
- A value like
#0055FFgets a name likecolor-primary-500instead of being pasted directly wherever that blue is needed - The same token name is used in both the design tool (Figma variables or styles) and the actual codebase (CSS custom properties, a theme object, platform resource files), keeping them in sync
- Changing a token’s value in one place updates every place that references it, instead of requiring a manual find-and-replace across the whole codebase
- Tokens are usually organized in tiers: primitive tokens hold raw values (
blue-500 = #0055FF), semantic tokens name a purpose and point at a primitive (color-primary = blue-500), component tokens scope a semantic token to one component (button-bg = color-primary) - A build pipeline (commonly Style Dictionary) transforms one token source file into multiple platform-specific outputs automatically
- Dark mode and theming work by swapping which primitive a semantic token points to, without touching a single component’s code
- A token can reference another token instead of a raw value, forming a small dependency chain that a build tool resolves down to a final concrete value
- Tokens can encode more than color: spacing scales, type scales, border radii, shadow definitions, animation durations, and breakpoints are all commonly tokenized
- Version-controlled token files let a design change go through the same pull-request review as any other code change
- Naming follows a predictable pattern, usually
category-property-variant-state, socolor-background-danger-hoveris unambiguous without needing to open the file to guess its purpose - Tools like Figma Variables, Tokens Studio, and Style Dictionary each handle a different part of the pipeline: capturing the value, storing the source file, and transforming it into platform output
- Token changes typically flow through the same CI pipeline as code: a pull request against
tokens.jsontriggers a build, a visual regression check, and a review before merging
Token Tiers
| Tier | Example | Purpose |
|---|---|---|
| Primitive | blue-500 = #0055FF | Raw value, no meaning attached |
| Semantic | color-primary = blue-500 | Names the value’s purpose |
| Component | button-bg = color-primary | Scopes a semantic token to one component |
| Alias | cta-bg = button-bg | Points at another token for a specific use case |
Under the Hood
The token source file is the single source of truth. It’s usually plain JSON or YAML, checked into version control like any other code artifact, not a screenshot or a wiki page. A build step reads that file once and emits a different, idiomatic format for each consuming platform: CSS custom properties for web, .xcassets or Swift constants for iOS, XML resources for Android.
This is what makes tokens more than a naming convention. Because the transformation is automated, updating one value in tokens.json and re-running the build regenerates every platform’s output correctly, with no risk of a human manually retyping the hex value wrong on one of the three platforms.
Semantic tokens add a layer of indirection that primitive tokens alone don’t provide. A component styled with button-bg: color-primary never needs to change when the brand color changes, only the mapping from color-primary to a primitive token does. This indirection is also exactly how a single component supports both a light and a dark theme: color-primary resolves to a different primitive depending on which theme context is active.
Worked Example 1
- Given: A
spacing-mdtoken is set to16pxand referenced by the padding of 30 different components across a product. - Step: A design review decides the product feels cramped and increases
spacing-mdto20pxin the token source. - Answer: All 30 components’ padding updates on the next build; no component’s code changes.
Worked Example 2
- Given: A product needs a dark mode.
color-surfaceis a semantic token currently mapped to the primitivewhite. - Step: A dark theme file remaps
color-surfaceto the primitivegray-900instead, without touching any component. - Answer: Every component using
color-surfacerenders correctly in dark mode automatically, because none of them ever referencedwhitedirectly.
Worked Example 3
- Given: A design audit finds 14 different hardcoded shades of blue used across a legacy codebase, none of them named or reused deliberately.
- Step: The team consolidates them down to 5 intentional primitive tokens (
blue-100throughblue-900) and replaces each hardcoded hex value with the nearest token. - Answer: Future color changes touch 5 named values instead of hunting through the codebase for scattered, undocumented hex codes.
Worked Example 4
- Given: A B2B SaaS product needs to white-label its dashboard for a client whose brand color is green instead of the product’s default blue.
- Step: The client’s build simply overrides
color-primaryat the semantic tier with a green primitive, leaving every component token and every component untouched. - Answer: A full-brand reskin ships without a single component being edited or redeployed differently.
Why It Matters
- Makes systemic design changes, a full rebrand or a dark mode, a matter of updating token values instead of hunting down every hardcoded value in the codebase
- Reduces the cost of supporting a new platform, since only a new output transform is needed, not a redesign of the values themselves
- Keeps design and engineering looking at the same source of truth instead of a design file slowly drifting from what’s actually shipped
- Enables theming (dark mode, white-labeling for different clients, high-contrast accessibility modes) without duplicating component code
- Makes design decisions reviewable and diffable in version control, the same way code changes are
- Cuts down on inconsistency that creeps in when many designers eyeball “close enough” colors and spacing independently
- Supports white-labeling and multi-brand products by swapping a token set instead of maintaining separate component code per brand
- Makes accessibility fixes, raising a contrast ratio, systemic: fix the token once instead of patching every screen that used the old value
- Lets designers and engineers speak the same vocabulary in code review and design review, “bump
space-4tospace-5” means the same specific thing to both
Common Pitfalls
- Defining tokens but still letting hardcoded values sneak into the codebase alongside them, undermining the whole point
- Creating too many overly specific tokens instead of a clean, small set of reusable values, recreating the same maintenance problem tokens were meant to solve
- Naming tokens after their appearance instead of their purpose, like
blue-buttoninstead ofcolor-primary, which breaks the moment the button needs to not be blue - Skipping the semantic tier and referencing primitive tokens directly from components, which makes theming impossible without editing every component
- Letting the token source file and the design tool drift apart, so a designer’s Figma variable no longer matches the shipped CSS variable of the same name
- Renaming a token without updating every reference, silently breaking a build instead of failing loudly
- Treating tokens as purely a color problem and forgetting to tokenize spacing, type scale, and motion, leaving those just as hardcoded as before
- Choosing token names that describe a specific screen instead of a reusable purpose, like
homepage-hero-blueinstead ofcolor-primary - Assuming every value needs its own token, some genuinely one-off values are fine hardcoded, and tokenizing them just adds indirection with no reuse benefit
Comparison
| Design Tokens | Hardcoded Values | CSS Variables Alone | Sass Variables | |
|---|---|---|---|---|
| Single source of truth | Yes | No | Partially | Partially |
| Cross-platform output | Yes, via build pipeline | No | No, web only | No, compile-time only |
| Runtime theme switching | Yes | No | Yes | No, resolved at compile time |
| Design-tool integration | Yes | No | No | No |
| Diffable in version control | Yes | Scattered across files | Yes | Yes |
| Consumed directly by design tools | Yes | No | No | No |
| Survives a rebrand without touching components | Yes | No | Partially | No |
| Works across web, iOS, and Android | Yes | No | No | No |
Example
Google’s Material Design 3 ships a full token system (md.sys.color.primary, md.sys.color.on-primary, and similar) that Android, Flutter, and web implementations all consume, so a single color scheme change propagates identically across every platform Google supports.
Salesforce’s Lightning Design System similarly publishes its full design token set as a versioned npm package, letting any team building on the platform pull in the same values a build pipeline would generate internally.
The W3C Design Tokens Community Group is actively standardizing a common token file format so that design tools and build pipelines from different vendors can read and write the same tokens.json structure without a custom converter for every tool pairing.
Related Terms
Referenced by