Name tokens by role and state, not by appearance
Aliases: semantic naming · color.bg.success · not color.green.600
What it is
A public name should read as a duty: color.bg.success is “background for the success role”, with a state tacked on when needed, as in color.bg.success.pressed. color.green.600 reads as a pigment. Pigments change; roles remain. Role-state naming makes the outward token name answer “what job, which state”, not “which swatch it looks like”. The primitive layer may use pigment names internally; that layer is not the public API for page authors. If page authors write color.green.600 into product code, the day success stops being that green — or stops being green — every occurrence is a lie or a corpus hunt.
Why it happens
A name is an index for someone who will not be in the design file months later. An appearance name pins the index to today’s sample: success is that step of green today, not tomorrow, so the index rots while the references remain. A role name pins the index to product meaning: success, danger, disabled, floating — words that follow the task, not the swatch. State hangs off role because the same duty takes different values at default, hover, pressed, disabled; writing the state as another pigment (“a darker green”) deletes the duty from the name, and callers fall back on memory or comments. The spoken order (kind · role · state) lets someone rule out mistakes without opening a file: a background will not be taken for a border, success will not be taken for danger. Appearance names cannot rule those out, because they never said kind or role.
Where it stops holding
Primitive palettes, weight axes, and spacing steps need unsplittable numbers or pigment names at the bottom, or there is nowhere to store the actual value; what is forbidden is lifting those names into page-level public references. Color in illustration and photography is not an interface role and need not be called color.bg.success. Sequential colors in data visualization (the third series, the seventh slice) often have no product role; numbering or hue names are honest — do not pretend every series is “success”. A brand spot used only in the mark may keep a pigment name, provided product UI is not allowed to reference it. Across languages, keep stable English keys in code and translate display names; putting a local phrase like “success-green” in the key makes rename and search hurt.
Applying it
- Allow pages and component implementations to reference role-bearing names only. Pigment and numbered names stay in the primitive file, out of product pull requests.
- Read every new token aloud: can it be spoken as “this kind, this role, this state”. If it reads as “that green” or “a bit larger”, send it back for a rename.
- On rebrand, change assignments behind role names, not the role names. If a rename is required, the original name was appearance; ship a rename migration.
- Check: search product repos for
green,blue,#, or raw type sizes as part of a token path. Hits are appearance-name leakage. Then show ten public token names to an engineer who did not build the system and ask for duty and state from the name alone; pigment answers, or no state, mean the name is not carrying the index. Swap the success assignment to something obviously different: every call still named*.successshould follow; every call named*.green.*should show up as a miss — those are the references this naming rule exists to kill.
Related
- Same group: R1.09.1 Component tokens serve one component and are not reused outside it · R1.09.3 Alias chains that run too deep make origin untraceable · R1.09.4 Scale tokens take stepped values; arbitrary numbers break the rhythm
- Adjacent: R1.01 Design tokens · R1.15 Multi-brand and multi-theme
- Search terms:
role-state naming·semantic alias·color.bg.success