No history yet

Design Token Architecture

The Language of Design

A design system's strength lies in its ability to translate abstract ideas into concrete code. Hard-coding values like #007bff or 16px directly into components creates a brittle system. When a brand color changes, you're left searching and replacing across dozens of files. This is not scalable.

Design tokens solve this by creating a shared language. They are named entities that store visual design attributes. Instead of using a raw hex code, you use a token like --color-brand-primary. This simple act of abstraction is transformative. It separates the raw value (the what) from its intended purpose (the why).

Effective token naming is semantic. It describes the token's role, not its value. Naming a color --blue-500 is useful, but naming it --color-interactive-default is powerful. The first describes a color; the second describes a job that needs doing.

Design tokens are the language your design speaks to your codebase.

A Three-Tiered Architecture

A robust token system isn't flat. It has layers of abstraction, each serving a specific purpose. We can structure this as a three-tiered system: Global, Alias, and Component tokens. This hierarchy provides both flexibility and control, making the system easy to maintain and theme.

Global Tokens are the primitive values, the absolute source of truth. They are context-agnostic and often generated directly from a design tool. They use literal names, like --blue-500 or --font-size-100. You should rarely, if ever, apply global tokens directly to a component.

/* :root { */
  /* Global Tokens: The raw values */

  /* Colors */
  --blue-500: #007bff;
  --gray-100: #f8f9fa;
  --gray-900: #212529;

  /* Spacing (Base unit) */
  --space-unit: 4px;

  /* Typography */
  --font-family-base: 'Inter', sans-serif;
  --font-weight-regular: 400;
  --font-weight-bold: 700;
/* } */

are the next layer. They consume global tokens and give them a specific purpose or context. This is where the semantic meaning comes to life. An alias token like --color-background-primary might point to var(--gray-100) in a light theme but var(--gray-900) in a dark theme. Aliases are the key to themeability. They bridge the gap between your raw color palette and its application in the UI.

/* :root { */
  /* Alias Tokens: Contextual roles */

  --color-background-primary: var(--gray-100);
  --color-text-default: var(--gray-900);
  --color-interactive-default: var(--blue-500);

  --font-body: var(--font-family-base);
  --font-weight-body: var(--font-weight-regular);
/* } */

Component Tokens are the most specific layer. These tokens are scoped to a single component and define its properties. They almost always consume alias tokens. This allows you to make a component-specific change without affecting the global aliases. For example, you might decide a specific button needs a different background color, so you'd override its component token.

.button {
  /* Component Tokens: Scoped to the button */
  --button-background-color: var(--color-interactive-default);
  --button-text-color: var(--color-background-primary);
  --button-padding: var(--space-2) var(--space-4);

  /* Applying the tokens */
  background-color: var(--button-background-color);
  color: var(--button-text-color);
  padding: var(--button-padding);
}

Systematic Scales

Consistency comes from systems, not just values. Instead of picking arbitrary numbers for spacing and font sizes, we should define them using a predictable, mathematical scale. This ensures visual harmony and rhythm throughout the user interface.

For spacing, a geometric scale is common. You start with a base unit and multiply it to create larger values. A 4px base unit is a popular choice, as it provides granular control and scales nicely on most displays.

:root {
  --space-unit: 4px;

  --space-1: calc(1 * var(--space-unit)); /* 4px */
  --space-2: calc(2 * var(--space-unit)); /* 8px */
  --space-3: calc(3 * var(--space-unit)); /* 12px */
  --space-4: calc(4 * var(--space-unit)); /* 16px */
  --space-5: calc(6 * var(--space-unit)); /* 24px */
  --space-6: calc(8 * var(--space-unit)); /* 32px */
}

For typography, we can achieve responsive and scalable text without media queries by using the CSS clamp() function. This function takes three arguments: a minimum value, a preferred value (often using viewport units), and a maximum value. This creates that scales smoothly with the viewport size, but never becomes too small or too large.

clamp(MIN,PREFERRED,MAX)clamp(MIN, PREFERRED, MAX)
:root {
  /* Fluid font size for a heading */
  --font-size-heading: clamp(1.75rem, 1rem + 2.5vw, 3rem);
}

h1 {
  font-size: var(--font-size-heading);
}

Color systems also benefit from logical naming. Instead of just naming colors, we can create a system based on their role. This often involves defining background colors (sometimes called holes), accents for interactive elements, and states like hover, focus, and disabled. This semantic approach makes it clear how to apply colors correctly.

Token NamePurpose
--color-background-primaryThe main background color of the application.
--color-background-secondaryA subtle, secondary background for containers.
--color-accent-primaryThe main interactive color for buttons, links.
--color-border-defaultThe standard border color for components.
--color-state-hoverThe background color for an element on hover.

With these structured systems for naming and scaling, you create a design system that is more than just a collection of styles. You build a predictable, maintainable, and themeable foundation that enables designers and developers to build cohesive experiences efficiently.

Quiz Questions 1/6

What is the primary problem that design tokens are intended to solve in a design system?

Quiz Questions 2/6

According to the principles of semantic naming, which token name is the most effective for defining the main interactive color of an application?