Hero image for "Semantic Token Names Don't Age — Descriptive Ones Do"

Semantic Token Names Don't Age — Descriptive Ones Do


Here's a failure mode that plays out on a predictable schedule: a team names their primary action color coral because the brand is warm and the designer loves it. Eighteen months later, the brand pivots. The coral becomes terracotta. Now you have a token named coral that is not coral, documentation that lies, and a new engineer asking why color.brand.coral renders orange.

This isn't a color problem. It's a naming problem — and it compounds.

Descriptive Names Feel Intuitive Until They Don't

The appeal of descriptive token names is obvious. coral, blue-600, spacing-24 — these are easy to understand in isolation. You don't need to know the system to read them. That's exactly why teams reach for them early.

The maintenance cost surfaces later. As ColorArchive Notes puts it: "When a brand color shifts from warm coral to cool terracotta, a token named 'coral' is now lying — it either needs to be renamed (touching every consumer) or left misleading." Renaming touches every component that references it. Leaving it creates the kind of quiet confusion that makes onboarding harder with every passing quarter.

Multiply that across a full palette that evolves across product generations, and you've built a system that punishes growth.

The same dynamic shows up in token linting audits. Always Twisted's breakdown of common token failures includes naming inconsistency as one of the most damaging silent failures — not because it breaks anything immediately, but because it compounds: "New developers don't know the convention, so they pick one. Inconsistency compounds, tooling starts to break, and onboarding gets harder with every new addition."

Semantic Names Survive Rebrand. Descriptive Names Don't.

The two-layer token architecture is the answer most mature systems converge on, and the reasoning is structural, not aesthetic.

The primitive layer holds raw values with concise descriptive names — teal-400, neutral-200, spacing-16. These are the source of truth for what values exist. No component should reference them directly.

The semantic layer sits above it, using role-based names: surface-primary, action-hover, text-secondary. Components only reference semantic tokens. When the brand changes, you update the mapping between semantic and primitive in one place. Everything downstream stays untouched.

GitLab's Pajamas design system makes the intent explicit: semantic tokens "use a naming strategy that helps clarify design intent and use." Their example — status.brand.background.color — tells you what the token is for, not what it looks like. That's the distinction that matters at scale.

Figma's token documentation frames the same idea from the workflow side: "instead of saying 'use #0D99FF,' you say 'use primary-blue,' and that name stays connected to the value everywhere it lives." The name, not the value, is what the rest of the system depends on.

The Code That Shows the Problem

Here's the failure mode in concrete form:

/* Descriptive — breaks on rebrand */
--color-coral: #E8735A;
--color-coral-dark: #C45A42;

/* Semantic — survives rebrand */
--color-action-primary: var(--color-coral);
--color-action-primary-hover: var(--color-coral-dark);

When the brand pivots, the descriptive version requires touching every component that references --color-coral. The semantic version requires updating exactly one mapping. The components never know anything changed.

Stuart Robson's practical guide (via Web Standards) reinforces the structural principle: prioritize clarity over brevity, use semantic intent over visual descriptions, and design for growth. The naming decision you make in week one shapes token discussions for years.

The Heuristic

Ask this question about every token name you're considering: Does this name tell you what the token does, or what it looks like right now?

If the answer is "what it looks like right now," it will create maintenance debt. Not immediately — but on the schedule of your next rebrand, your next platform expansion, or your next engineer who joins without context.

Descriptive names at the primitive layer are fine and useful. Descriptive names at the semantic layer are a liability. The moment a component references coral instead of action-primary, you've coupled your component to a visual decision that will change. The semantic layer exists precisely to absorb that change so components don't have to.

Name for what it does. Let the primitive layer handle what it looks like.