Deep Dive: Token Naming & Hierarchy

Why Naming Matters

Token names are API design. They're the interface between design decisions and implementation—the contract that designers, developers, and tooling all depend on. A poorly named token creates confusion, duplication, and technical debt. A well-named token communicates intent, enables discovery, and scales gracefully.

Unlike code variables that can be refactored with IDE tooling, token names propagate across design tools, documentation, CSS output, and TypeScript types. Renaming a token is a breaking change that ripples through the entire system. This makes getting names right from the start essential.

The Naming Formula

Every token name follows a consistent pattern that encodes its layer, category, and purpose:

[layer].[category].[subcategory].[variant].[state]

Examples:
core.color.palette.neutral.600
semantic.color.foreground.primary
semantic.components.button.primary.background
semantic.spacing.gap.grid

Layer Prefix (Required)

Every token starts with its layer prefix. This immediately communicates where the token lives in the hierarchy and what it can reference:

PrefixPurposeCan Reference
core.Raw primitives with no semantic meaningNothing (leaf nodes with raw values)
semantic.Purpose-driven roles and aliasescore.* or other semantic.* tokens
semantic.components.UI-specific bindingssemantic.* or core.* tokens

Category (Required)

The category groups tokens by their fundamental type. This enables filtering, tooling, and mental models:

CategoryWhat It ContainsExamples
colorAll color valuespalette, foreground, background, border, status
spacingSpatial dimensionssize scale, gap, padding, margin
typographyText-related valuesfamily, weight, ramp, lineHeight, letterSpacing
motionAnimation propertiesduration, easing, delay, stagger
shapeGeometric propertiesradius, border
elevationDepth and layeringshadow, depth, level
componentsComponent-specific tokensbutton, input, card, badge

Subcategory (Context-Dependent)

Subcategories provide additional grouping within a category. Their structure depends on the layer:

// Core: Subcategory describes the value type
core.color.palette.neutral.600    // "palette" = color scale
core.color.mode.dark              // "mode" = theme base colors
core.spacing.size.04              // "size" = spacing scale

// Semantic: Subcategory describes the role
semantic.color.foreground.primary // "foreground" = text/icon colors
semantic.color.background.danger  // "background" = surface colors
semantic.color.border.subtle      // "border" = boundary colors
semantic.color.status.success     // "status" = feedback colors

Variant and State (Optional)

Variants describe visual weight or emphasis. States describe interactive conditions:

// Variants (visual weight)
semantic.components.button.primary.background
semantic.components.button.secondary.background
semantic.components.button.danger.background

// States (interactive conditions)
semantic.components.button.primary.background.hover
semantic.components.button.primary.background.active
semantic.components.button.primary.background.disabled

Naming Principles

1. Describe Purpose, Not Implementation

Token names should communicate what something is for, not what it looks like. This enables theming and evolution without breaking names.

// BAD: Describes implementation
semantic.color.blue500
semantic.color.grayText
semantic.spacing.16px

// GOOD: Describes purpose
semantic.color.foreground.link
semantic.color.foreground.secondary
semantic.spacing.gap.grid

2. Use Nouns for Tokens, Verbs for Utilities

Tokens represent values (nouns). Utilities and functions represent actions (verbs). This distinction keeps the mental model clear.

// Tokens (nouns) - represent values
semantic.color.foreground.primary
semantic.motion.duration.short
semantic.elevation.shadow.raised

// Utilities (verbs) - represent actions
getTokenValue('semantic.color.foreground.primary')
resolveReference('{core.color.palette.blue.500}')
validateToken(tokenDefinition)

3. Maintain Consistent Depth

Tokens at the same conceptual level should have the same depth. Avoid skipping hierarchy levels or creating inconsistent structures.

// BAD: Inconsistent depth
semantic.color.primary           // 3 levels
semantic.color.foreground.primary // 4 levels
semantic.color.background.surface.raised // 5 levels

// GOOD: Consistent depth within category
semantic.color.foreground.primary
semantic.color.foreground.secondary
semantic.color.foreground.tertiary
semantic.color.background.primary
semantic.color.background.secondary
semantic.color.background.raised

4. Use American English Spelling

For consistency across the codebase, use American English spelling. This aligns with CSS property names and most programming conventions.

// BAD: British spelling
semantic.color.grey.500
semantic.color.foreground.colour

// GOOD: American spelling
semantic.color.gray.500
semantic.color.foreground.color

5. Prefer Explicit Over Abbreviated

Clarity beats brevity. Abbreviated names save a few characters but cost discoverability and understanding.

// BAD: Abbreviated
semantic.clr.fg.prim
semantic.typ.wt.bd
semantic.spc.sz.04

// GOOD: Explicit
semantic.color.foreground.primary
semantic.typography.weight.bold
semantic.spacing.size.04

Hierarchy Patterns

Core Token Hierarchy

Core tokens organize raw values by their type. The hierarchy reflects the nature of the value, not its usage:

core/
├── color/
│   ├── palette/
│   │   ├── neutral/     # 100-800 grayscale
│   │   ├── red/         # 100-800 red scale
│   │   ├── blue/        # 100-800 blue scale
│   │   └── ...
│   ├── mode/
│   │   ├── light        # Base light color
│   │   ├── dark         # Base dark color
│   │   └── transparent  # Transparent
│   └── datavis/         # Chart colors
│
├── spacing/
│   └── size/
│       ├── 00           # 0
│       ├── 01           # 1px
│       ├── 02           # 2px
│       └── ...          # up to 10 (64px)
│
├── typography/
│   ├── family/          # Font families
│   ├── weight/          # Font weights
│   ├── ramp/            # Size scale
│   ├── lineHeight/      # Line height ratios
│   └── letterSpacing/   # Letter spacing values
│
├── motion/
│   ├── duration/        # Timing values
│   ├── easing/          # Easing curves
│   └── delay/           # Delay values
│
├── shape/
│   ├── radius/          # Border radii
│   └── border/          # Border styles
│
└── elevation/
    ├── shadow/          # Box shadows
    └── depth/           # Z-index layers

Semantic Token Hierarchy

Semantic tokens organize values by their purpose in the UI. The hierarchy reflects usage patterns and design decisions:

semantic/
├── color/
│   ├── foreground/
│   │   ├── primary      # Main text
│   │   ├── secondary    # Supporting text
│   │   ├── tertiary     # Subtle text
│   │   ├── link         # Link text
│   │   └── inverse      # Text on dark backgrounds
│   ├── background/
│   │   ├── primary      # Main surface
│   │   ├── secondary    # Alternate surface
│   │   ├── brand        # Brand-colored surface
│   │   └── danger       # Error/warning surface
│   ├── border/
│   │   ├── default      # Standard borders
│   │   ├── subtle       # Light borders
│   │   └── strong       # Emphasized borders
│   └── status/
│       ├── info         # Informational
│       ├── success      # Positive
│       ├── warning      # Caution
│       └── danger       # Error/critical
│
├── spacing/
│   ├── gap/             # Flex/grid gaps
│   ├── padding/         # Internal spacing
│   └── margin/          # External spacing
│
├── components/
│   ├── button/
│   │   ├── primary/
│   │   │   ├── background
│   │   │   ├── foreground
│   │   │   └── border
│   │   ├── secondary/
│   │   └── danger/
│   ├── input/
│   ├── card/
│   └── ...

Pitfalls to Avoid

1. Color Names in Semantic Tokens

Never use color names in semantic tokens. This couples the name to a specific implementation and breaks when themes change.

// BAD: Color name in semantic token
semantic.color.blueButton
semantic.color.redError
semantic.color.greenSuccess

// GOOD: Purpose-based names
semantic.color.background.brand
semantic.color.status.danger
semantic.color.status.success

2. Size Values in Names

Avoid embedding specific values in token names. Use relative terms or scale positions instead.

// BAD: Values in names
semantic.spacing.16px
semantic.typography.fontSize14
semantic.motion.duration200ms

// GOOD: Relative or scale-based names
semantic.spacing.size.04
semantic.typography.size.body
semantic.motion.duration.short

3. Inconsistent Pluralization

Be consistent with singular vs plural. Generally, use singular for categories and plural for collections.

// BAD: Inconsistent pluralization
semantic.colors.foreground.primary
semantic.color.backgrounds.primary
semantic.component.button.primary

// GOOD: Consistent (singular categories)
semantic.color.foreground.primary
semantic.color.background.primary
semantic.components.button.primary

4. Overloaded Names

Each token should have one clear purpose. Avoid names that could apply to multiple contexts.

// BAD: Ambiguous names
semantic.color.primary        // Primary what? Text? Background?
semantic.spacing.default      // Default for what context?
semantic.border.main          // Main border color? Width? Style?

// GOOD: Specific names
semantic.color.foreground.primary
semantic.spacing.gap.grid
semantic.color.border.default

5. Skipping Hierarchy Levels

Don't skip levels in the hierarchy. This creates inconsistent paths and breaks tooling expectations.

// BAD: Skipped levels
semantic.primary                    // Missing category
semantic.color.primary              // Missing subcategory
semantic.components.background      // Missing component name

// GOOD: Complete hierarchy
semantic.color.foreground.primary
semantic.color.background.primary
semantic.components.button.primary.background

Naming for Discoverability

Good naming enables discovery through autocomplete, search, and browsing. Consider how developers will find tokens:

Autocomplete-Friendly

Names should narrow down progressively. Start broad (layer), then category, then specifics:

// Typing "semantic.color." shows:
semantic.color.foreground.*
semantic.color.background.*
semantic.color.border.*
semantic.color.status.*

// Typing "semantic.color.foreground." shows:
semantic.color.foreground.primary
semantic.color.foreground.secondary
semantic.color.foreground.tertiary
semantic.color.foreground.link

Search-Friendly

Names should be searchable by common terms. Include the most likely search terms in the path:

// Searching "button" finds:
semantic.components.button.*

// Searching "error" or "danger" finds:
semantic.color.status.danger
semantic.color.background.danger
semantic.components.button.danger.*

Summary

  • Layer prefix is required—core., semantic., or semantic.components.
  • Describe purpose, not implementation—foreground.primary not gray600
  • Use nouns for tokens, verbs for utilities
  • Maintain consistent depth within categories
  • Prefer explicit over abbreviated names
  • Avoid color names, size values, and ambiguous terms in semantic tokens

Well-named tokens are an investment that pays dividends in maintainability, discoverability, and team velocity. Take the time to get names right—your future self and your team will thank you.

Next Steps

With naming conventions established, explore how tokens enable multi-brand theming, how the resolver module handles context-aware resolution, and how schema validation enforces these conventions automatically.

← Back to Design Tokens