Title: EDS Tokens naming rules
Status: Draft
Author: vnys
Date: Nov 20 2022
Token names should be descriptive enough to understand the context, but not overly elaborate when the meaning is clear – unless it makes using the tokens easier. For example, including typography and font-size in the same token is uneccessary. All tokens are namespaced with eds. While this adds a seemingly uneccessary layer for EDS authors, it ensures that the EDS tokens can be used by product teams who build their own tokens on top of EDS who can then use their own namespace to make it clear internally what’s in the EDS domain and what’s in their product’s domain.
The method used is based on the original “Naming Tokens in Design Systems” article by Nathan Curtis from 2018, the “Naming design tokens” article by Lukas Oppermann from 2022, In the file - Building a headless design system on YouTube by Esther Cheran from the Figma Tokens team, Token Zen Garden, also by Esther Cheran – as well as looking at the tokens from Adobe Spectrum and others.
There’s a companion spreadsheet that’s been used in this work, ask for permission if you need access.
- Some keywords can appear in more than one segment
- In some cases it makes sense to change the wording slightly as a consequence of this, for example:
- Categories are plural, i.e. font-families, line-heights
- Properties are singular, i.e. font-family, line-height
- In some cases it makes sense to change the wording slightly as a consequence of this, for example:
- The tier names core and semantic are included in the token name
- The tier name component is left out of the token name, because the name of the component makes the tier obvious
- The segments in a token name should conceptually be similar
- For example: A developer should be able to iterate over all the variants of a component without having to filter out properties on the same level
- Note: Is this doable? 🤔
- Tokens makes sense for designers, perhaps less so for developers
- For example, the list-item component tokens has the following structure:
{
"list-item": {
"text-color": {},
"default": {
"label": {}
},
"featured": {
"label": {}
},
"icon-color": {},
"space-between": {}
}
}
In this case properties and variants are mixed at the same level, which can be confusing and hard to iterate over in code. Perhaps adding a semantic layer would make it easier to work with:
{
"list-item": {
"props": {
"icon-color": {},
"space-between": {},
"text-color": {}
},
"variants": {
"default": {
"label": {}
},
"featured": {
"label": {}
}
}
}
}
Perhaps this is also an indicator that creating / editing tokens in JSON leads to a better structure? 🤔
If we aim to group tokens semantically it does lead to longer token names, and also make the following token names problematic:
--eds-button-primary-filled-hover-background-color
--eds-button-primary-filled-hover-label-text-color
One solution to this problem would be to remove label from the second token, as the label would inherit the colour from the parent anyway.
--eds-button-primary-filled-hover-background-color
--eds-button-primary-filled-hover-text-color
Another solution would be to add a semantic layer:
--eds-button-primary-filled-hover-props-background-color
--eds-button-primary-filled-hover-elements-label-text-color
⚠️ Warning Adding a semantic layer breaks with other token conventions, an investigation needs to take place to uncover why nobody else seem to do this
- Identifier to the left
- Common properties are grouped into semantic tokens
- The object segments component and element are separated by the modifier segments variant, type and state
- The rationale behind this is that in the case of the button label for example, it’s not the label that’s in a primary variant, filled type and hover state, but it’s parent.
- For properties that are common for several types, variants and states, we use allTypes, allVariants and allStates. That way the button token name always has six segments, and knowing that the state always is segment number 5 makes the tokens predictable to work with. The exception to this rule are the composition tokens, which are used for the shapes – and are grouped under the keyword “elements”.
system | group | component | type | variant | state | element | concept | property |
---|---|---|---|---|---|---|---|---|
eds | button | primary | ghost | hover | border-color | |||
eds | button | primary | ghost | hover | label | text-color | ||
eds | button | allTypes | allVariants | disabled | text-color | |||
eds | button | padding-x | ||||||
eds | button | label | padding-x | |||||
eds | button | element | ...properties |
An alternative syntax that we want to test on the product teams is to introduce an optional group level after the component name. The advantage of this syntax is that it’s easier to work with in code, in Figma, however, the result is more levels before getting to the actual value.
system | component | group | type | variant | group | state | element | concept | property |
---|---|---|---|---|---|---|---|---|---|
eds | button | states | background-color | ||||||
eds | button | types | primary | filled | props | text-color | |||
eds | button | types | primary | filled | states | hover | text-color | ||
eds | button | elements | label | ...properties |
Some names can be both categories and properties. One example would be background. In this case, using background as a category name can be shortened to bg. In some cases we also need to combine two categories. One example would be color and fg.
Some names can be both categories and properties. One example would be background. In this case, using background as a category name can be shortened to bg. In some cases we also need to combine two categories. One example would be color and fg.
There are two different categories of semantic tokens, one simple and one complex. Observe, for example, the difference between the following two examples:
--eds-spacing
- Has category
- Adds tier name
- Less specific tokens have category in the name
- More specific tokens does not
system | tier | group | category | category | variant | type | state | concept | property |
---|---|---|---|---|---|---|---|---|---|
eds | semantic | forms | inputs | border-color | |||||
eds | semantic | color | fg | warning | |||||
eds | semantic | typography | font-families | default | |||||
eds | semantic | font-families | default | ||||||
eds | semantic | font-families | mono | ||||||
eds | semantic | color |
While semantic tokens are decisions, core tokens are options that are referenced, or aliased, in semantic tokens. Core tokens are never referenced directly in a component or a component token, as that would make theming impossible.
Some examples of core tokens are:
system | tier | group | category | category | color name | variant | type | state | concept | property | scale |
---|---|---|---|---|---|---|---|---|---|---|---|
eds | core | typography | line-heights | tight | |||||||
eds | core | color | moss-green | 100 |
ℹ️ Note to self: The tokens in Figma has a “type” attribute, so adding the type to the token name is not strictly necessary – it can be added in code. The upside of skipping it is shorter token names, the downside is when you’re looking for a value in a list, it’s nice to be able to filter on type. Also having the same structure in Figma and in code could be beneficial.