# Name design tokens so nobody has to guess > Put the parts of every token name in one fixed order and people can guess names instead of looking them up. Renames go through an alias, never a break. - Source: https://flashdsm.com/blog/naming-design-tokens - Published: 2026-09-11 - Author: Flash DSM Team - Track: Fundamentals - Reading time: 5 min read --- ## Names outlive values Token names are the public API of your design system. Designers pick from them in Figma, engineers type them hundreds of times a week, and AI coding tools pattern-match on them. Values change freely. Names stick around until someone pays for a migration. A good name tells you what the token is for and roughly how it relates to its neighbours, without opening the docs. A bad one makes people guess, and people who guess pick the wrong token or give up and paste a hex. ## One order for every name Pick an order for the parts of a name and never break it. This one works for most systems: ```text category - property - variant - state ``` | Part | Answers | Examples | |---|---|---| | Category | What kind of value? | `color`, `space`, `radius`, `font-size`, `shadow`, `duration` | | Property | What role or element? | `surface`, `text`, `border`, `primary`, `inset`, `control` | | Variant | Which one? | `raised`, `muted`, `danger`, `on-primary`, `sm`, `lg` | | State | When? | `hover`, `pressed`, `focus`, `disabled`, `selected` | Category and property are required. Variant and state appear only when you need them: ```css --color-surface --color-surface-raised --color-text-muted --color-text-on-primary --color-border-focus --color-primary-hover --space-inset-md --radius-control ``` Read `color-text-on-primary` left to right and it's a sentence: the colour of text that sits on primary. If a name reads as a description of its job, the grammar is working. Keep state last, always. `--color-primary-hover` sorts next to `--color-primary` in every token list, and searching for `-hover` finds every hover token in the system. Put state in the middle once and both of those stop being true. > [!TIP] > Add a system prefix if your tokens end up in other people's pages. `--acme-color-surface` won't collide with a third-party widget that also defines `--color-surface`. ## Good names, bad names | Bad | What goes wrong | Better | |---|---|---| | `--blue` | The hue is the meaning, so a rebrand breaks it | `--color-primary` | | `--color-light-grey-bg` | Wrong the moment dark mode ships | `--color-surface-sunken` | | `--text-color-2` | A number with no order anyone remembers | `--color-text-muted` | | `--red-text` | Hue again, and the parts are backwards | `--color-text-danger` | | `--spacing-16px` | The value is in the name; it lies after the first change | `--space-4` or `--space-md` | | `--surface-v2` | There will be a v3 | `--color-surface-raised` | | `--primaryColor` | Different case style from everything else | `--color-primary` | | `--header-padding` | A component name in the shared tier | `--space-inset-lg`, or a component token | | `--color-button-primary-background-default-rest` | Seven parts to say one thing | `--button-bg` | Most bad names fall into two groups. Some describe the value (blue, light grey, 16px), which is the primitive tier's job. Others describe one place it's used (header, v2), which is a component's job. Semantic names describe a role, and nothing else. ## T-shirt sizes or numbers There are two ways to name the steps of a scale, and they suit different jobs. **T-shirt sizes** (`xs`, `sm`, `md`, `lg`, `xl`) are easy to say out loud and hard to misuse. They fit short scales where the relationship matters more than the value: radius, elevation, the handful of text sizes in a small product. The weakness is insertion. When you need something between `sm` and `md` there's no good name for it, and by `3xl` people are counting x's. **Numbers** come in two flavours: - **Multipliers** tie the name to a base unit. On a 4px grid, `space-1` is 4px, `space-4` is 16px and `space-6` is 24px. You can work out the value from the name, which engineers like. - **Ordinal steps** (`100` to `900`, or `0` to `1000`) say nothing about the value, only the order, and leave gaps. `550` fits between `500` and `600` without renaming anything. That's why colour ramps almost always use them. | Scale | Best fit | Why | |---|---|---| | Colour ramps | Ordinal numbers | Many steps, and you'll need to insert one | | Spacing | Multipliers | The name maps to the grid | | Radius | T-shirt | Few steps, `sm` and `lg` say enough | | Shadow | T-shirt or 1 to 5 | Elevation is short and ordered | | Font size | Either | T-shirt for a small product, numbers for a long type scale | | Duration | Named (`fast`, `base`, `slow`) | People choose by feel, not by milliseconds | You can mix styles across tiers. Primitives use numbers and semantics put t-shirt sizes on top: `--space-inset-md: var(--space-4)`. What you can't do is mix inside one scale. `space-sm`, `space-4` and `space-large` in the same list means nobody knows which is bigger. ## Renaming without breaking people You will rename tokens. The job is to never make it a single breaking change. 1. **Add the new name** with the same value. 2. **Turn the old name into an alias** of the new one, so both resolve identically. 3. **Mark the old name deprecated** where tools can see it. The W3C DTCG format has a `$deprecated` property that takes `true` or a string explaining what to use instead. 4. **Warn in code.** A lint rule or build step flags the old name and prints the replacement. 5. **Migrate usage.** Token names are plain text, so a codemod or a careful find-and-replace does most of it. 6. **Delete the alias** in a major version, after consumers have had at least one release to move. In DTCG JSON, steps 2 and 3 look like this: ```json { "color": { "bg-subtle": { "$type": "color", "$value": "{color.surface-sunken}", "$deprecated": "Use color.surface-sunken. Removed in 4.0." } } } ``` And in CSS the alias is one line: ```css /* Deprecated: use --color-surface-sunken. Removed in 4.0. */ --color-bg-subtle: var(--color-surface-sunken); ``` Old code keeps working, new code uses the new name, and a search for the alias tells you who hasn't moved yet. > [!WARNING] > Never rename a token and change its value in the same release. If something looks off afterwards, nobody can tell whether the rename or the value caused it. ## The checklist Keep this next to your token file: - Every name follows one grammar: category, property, variant, state, in that order. - One case style everywhere. Kebab-case in CSS, with JSON groups that mirror it. - No hues in semantic names. No hex, px or rem values in any name. - No theme names like `-dark` or `-light`. Themes change values, not names. - State is always the last part. - A new token has to do a job that no existing token does in any theme. - Every fill colour has an `on-` partner for the text and icons on top of it. - Each scale uses one naming style, with room to insert a step. - Component names appear only in component tokens. - Deprecated names alias to their replacement and say when they'll be removed. - Someone new can read the name aloud and guess where it goes. Flash generates names in this shape: semantic roles like surface, text, primary and border on top of ramps numbered 0 to 1000. The Documentation view puts a copy chip on every token, so people grab the real name instead of retyping it from memory. Every `on-` pair in that checklist exists to pass a contrast threshold, and [WCAG AA contrast in practice](/blog/contrast-wcag-aa-in-practice) has the numbers behind them.