Skip to content
fearchitect
Styling & Design Systems

Design Tokens & Theming

Named design decisions that flow from source to every platform.

By Abas TurabliReviewed

Summary

Design tokens are named values — colors, spacing, radii — stored once and transformed to CSS custom properties, iOS Swift, Android XML, or any output via a build tool such as Style Dictionary. A three-tier model (primitive → semantic → component) separates raw values from intent, making light/dark and brand swaps a single file change rather than a search-and-replace.

Jump to the interview angle

Three-tier token model

Tokens are organized in three layers. Primitive tokens are raw values: --color-blue-500: #3b82f6. They have no meaning beyond the value itself. Semantic tokens reference primitives and carry intent: --color-action-primary: var(--color-blue-500). Component tokens scope a semantic to one component: --button-bg: var(--color-action-primary). This indirection means swapping themes only touches the semantic layer — primitives and components stay unchanged.

Tokens flow from a single JSON source through Style Dictionary to platform-specific outputs; the three tiers sit inside the CSS output.

CSS custom properties theme swap

Semantic tokens live on :root; the dark theme overrides them on [data-theme='dark']. Components reference only semantic tokens, so switching themes is one attribute change on <html>.

Light/dark theme via CSS custom propertiescss
/* primitives — raw values, never used by components directly */
:root {
  --color-gray-50: #f9fafb;
  --color-gray-900: #111827;
  --color-blue-500: #3b82f6;
}

/* semantic tokens — default (light) theme */
:root {
  --color-surface: var(--color-gray-50);
  --color-text-primary: var(--color-gray-900);
  --color-action-primary: var(--color-blue-500);
}

/* dark theme override — only semantic layer changes */
[data-theme="dark"] {
  --color-surface: var(--color-gray-900);
  --color-text-primary: var(--color-gray-50);
  --color-action-primary: var(--color-blue-500); /* same primitive, different context */
}

/* component — references semantic only */
.btn-primary {
  background: var(--color-action-primary);
  color: var(--color-surface);
}

Toggle data-theme="dark" on <html> and every component updates instantly — zero JS rerenders, zero class churn.

Build-time vs runtime theming

ApproachHow it worksPerf costFlexibility
Build-time (CSS files)Style Dictionary emits one CSS file per theme at buildZero runtime cost; ship only active themeNoneTheme switch requires page reload or separate stylesheet swap
Runtime (CSS custom props)One stylesheet; JS sets `data-theme` attribute on `<html>`Single CSS parse; no JS bundle cost per themeMinimalInstant switch; supports user preference + OS sync
Runtime (JS-in-CSS / CSS-in-JS)Theme object injected into component styles at renderRe-runs style computation per render; ~20 ms overhead at scaleHighFully dynamic; token values can be computed at runtime

Flash of unstyled theme (FOUT)

When the active theme is set by JS after HTML parse, users see a flash of the default theme. Fix it by inlining a <script> that reads localStorage and sets data-theme before the first paint — or by defaulting to the OS preference with prefers-color-scheme in CSS and only overriding on explicit user choice.

Interview angle

Interviewers test whether you can explain why three tiers exist and how build-time vs runtime theming differ in cost and flexibility. Know Style Dictionary as the concrete tool.

Soundbite: "Semantic tokens decouple intent from value — change the theme file, not every component."

Key terms

Design token
A named design decision (color, spacing, radius) stored as a platform-agnostic value and transformed to target outputs.
Primitive token
A raw value with no semantic meaning, e.g. `--color-blue-500: #3b82f6`.
Semantic token
A token expressing intent by referencing a primitive, e.g. `--color-action-primary`.
Style Dictionary
Amazon's open-source build tool that transforms a token JSON source into CSS, Swift, Android XML, and other platform outputs.
CSS custom property
A variable declared with `--name: value` and read with `var(--name)`; reassignable at any scope for runtime theming.

Further reading

Search fearchitect

Jump to a topic, mode, or action.