Design Token References
Design Token References
Design token references enable tokens to derive their values from other tokens, creating relationships and abstraction layers within the token system. References are the mechanism behind semantic tokens, theme switching, and systematic design changes. Understanding how references work is fundamental to effective token architecture.
What Are Design Token References
Design token references are pointers from one token to another, indicating that the referencing token should resolve to the same value as the referenced token. Instead of containing a direct value, a referencing token contains an identifier pointing to another token.
References create aliases, where one token name represents the same value as another. This aliasing enables multiple layers of abstraction without duplicating values.
How Design Token References Work
References use syntax that distinguishes them from direct values:
Curly brace syntax (W3C spec aligned):
{
"color": {
"primitive": {
"blue": { "$value": "#3B82F6" }
},
"action": {
"primary": { "$value": "{color.primitive.blue}" }
}
}
}
The token color.action.primary references color.primitive.blue, inheriting its value.
Resolution process:
- Parser encounters reference syntax
- Reference path is extracted (
color.primitive.blue) - Referenced token is located in the dictionary
- Referenced value replaces the reference
- Process repeats if referenced token also contains a reference
Chain resolution:
{
"color": {
"primitive": { "blue": { "$value": "#3B82F6" } },
"semantic": { "action": { "$value": "{color.primitive.blue}" } },
"component": { "button": { "$value": "{color.semantic.action}" } }
}
}
color.component.button resolves through the chain to ultimately equal #3B82F6.
Build output contains resolved values:
:root {
--color-primitive-blue: #3B82F6;
--color-semantic-action: #3B82F6;
--color-component-button: #3B82F6;
}
Runtime CSS might preserve references for theming:
:root {
--color-primitive-blue: #3B82F6;
--color-semantic-action: var(--color-primitive-blue);
--color-component-button: var(--color-semantic-action);
}
Key Considerations
- References must point to existing tokens or builds fail
- Circular references create infinite loops and must be prevented
- Reference depth affects build performance and debugging
- References should flow from higher abstraction to lower
- Tooling should validate references before transformation
- Documentation should clarify reference relationships
- Renaming referenced tokens affects all referencing tokens
- Some platforms may not support runtime reference resolution
Common Questions
How should circular references be prevented?
Circular references occur when token A references token B, and token B (directly or through a chain) references token A. This creates an unresolvable loop.
Detection during build:
function detectCircular(token, path = []) {
if (path.includes(token.name)) {
throw new Error(`Circular reference: ${path.join(' -> ')} -> ${token.name}`);
}
if (token.reference) {
const referenced = getToken(token.reference);
detectCircular(referenced, [...path, token.name]);
}
}
Prevention through architecture:
- Enforce tier direction (primitives never reference semantics)
- Use linting rules that flag potential circular paths
- Review reference additions carefully
Tooling support: Style Dictionary and similar tools detect circular references and fail builds with descriptive error messages.
What is the difference between build-time and runtime references?
Build-time resolution replaces references with resolved values during transformation:
/* Output after build */
--color-primary: #3B82F6;
--color-action: #3B82F6;
Both properties contain the same value. No relationship exists at runtime.
Runtime resolution preserves reference relationships in output:
/* Output preserving references */
--color-primary: #3B82F6;
--color-action: var(--color-primary);
--color-action continues to reference --color-primary. Changing --color-primary at runtime automatically updates --color-action.
When to use each:
- Build-time: Simpler debugging, no runtime overhead, works everywhere
- Runtime: Enables dynamic theming, live customization, runtime value changes
CSS custom properties with var() naturally support runtime references. Other platforms typically use build-time resolution only.
How should references be documented?
Reference documentation helps developers understand token relationships.
Visual diagrams show reference flows:
color.primitive.blue ──────────────┐
↓
color.semantic.action.primary ─────┼── (references)
↓
color.component.button.background ─┘
Generated documentation can trace reference chains:
## color.button.background
- Value: #3B82F6
- References: color.semantic.action.primary
- Which references: color.primitive.blue
Tooling reports list reference relationships:
Reference Analysis:
- color.primitive.blue: Referenced by 12 tokens
- color.semantic.action.primary: References color.primitive.blue, Referenced by 5 tokens
Documentation should make it clear which tokens are aliases and what they ultimately resolve to.
Summary
Design token references enable tokens to derive values from other tokens, creating the aliasing that powers semantic layers and theming. References use special syntax that build tools resolve during transformation. Circular references must be prevented through architectural rules and tooling detection. The choice between build-time and runtime resolution affects theming capabilities and debugging. Clear documentation of reference relationships helps developers understand token dependencies.
Buoy scans your codebase for design system inconsistencies before they ship
Detect Design Drift Free