← Back to Insights

Design Tokens: One Change, Every Platform

Metasphere Engineering 5 min read

You open a pull request that changes the primary brand color. On web, the new color looks correct. On iOS, it’s two shades darker because someone hardcoded the old hex value in three SwiftUI views. On Android, it’s the original color entirely because the XML resource file was never connected to any shared source. The design team’s Figma file shows a fourth shade that matches none of the three implementations. Four platforms. Four different blues. Zero coordination.

Four platforms, four workflows, nobody noticed until a quarterly review. Multiply by every color, spacing value, and font size. That’s why consistency breaks at scale.

Key takeaways
  • Design tokens are the single source of truth for visual properties. Color, spacing, typography, elevation. Defined once, generated for every platform.
  • Three taxonomy levels: global tokens (raw values), alias tokens (semantic meaning like color-action-primary), component tokens (scoped to specific widgets).
  • Token pipelines generate platform outputs automatically. CSS custom properties, iOS Swift enums, Android XML resources, Figma variables. All from the same JSON source.
  • Dark mode is the first real test of token architecture. If switching themes requires touching component code, tokens aren’t properly layered.
  • FOUT (Flash of Unstyled Tokens) happens when token CSS loads after component CSS. Inline critical token values or ensure they load first.

The W3C Design Tokens Community Group is standardizing the interchange format.

Token Taxonomy: Global, Alias, Component

Prerequisites
  1. Design team agrees on a spacing scale (e.g., 4px base unit)
  2. Color palette finalized with light and dark variants for every semantic role
  3. Typography scale defined with at most 6-8 size steps
  4. At least one consuming platform (web, iOS, Android) ready to integrate token output
  5. Git repository established as the canonical source for token definitions

A flat list of 800 names is a constants file, not a system. Three layers hold up in production.

{
  "global": {
    "blue-500": { "value": "#1A2980" },
    "space-4": { "value": "16px" },
    "font-size-3": { "value": "1rem" }
  },
  "alias": {
    "color-interactive": { "value": "{blue-500}" },
    "color-surface": { "value": "{white}", "darkValue": "{gray-900}" },
    "spacing-component-gap": { "value": "{space-4}" }
  },
  "component": {
    "button-primary-bg": { "value": "{color-interactive}" },
    "card-padding": { "value": "{spacing-component-gap}" }
  }
}

Global tokens: raw values (blue-500: #1A2980). Never reference directly in components. Alias tokens: semantic meaning (color-interactiveblue-500). Theme switching lives here. Component tokens: bind decisions to specific widgets (button-primary-bgcolor-interactive).

Skip alias tokens and reference globals directly? You’ll rewrite every component when dark mode arrives. Weeks of refactoring that a single abstraction layer would have prevented.

Multi-Platform Token Distribution

PlatformOutput FormatGenerated FromExample
WebCSS custom propertiestokens.jsonvariables.css--color-interactive: #1A2980
iOSSwift constantstokens.jsonColors.swiftstatic let interactive = UIColor(hex: "#1A2980")
AndroidXML resourcestokens.jsoncolors.xml<color name="interactive">#1A2980</color>
React NativeJS style objectstokens.jsontokens.tsinteractive: '#1A2980'
FigmaPlugin synctokens.json → Figma variablesBidirectional with Tokens Studio

Style Dictionary is the standard tool for this transformation. Define tokens once. Run a build. Get CSS custom properties, iOS Swift constants, Android XML values, and React Native style objects from the same source file.

In production, plan for 20-30 custom transforms. iOS needs CGFloat, Android needs dp, CSS needs rem for fonts but px for borders. That’s where the real engineering hours go.

Token Studio bridges Figma to Git. Designers change tokens in Figma, the plugin opens a PR. CI runs Style Dictionary. No more “I updated colors in Figma, can someone update the code?”

Platform packages are versioned and published to internal registries. Consuming apps pin and upgrade explicitly.

Design token pipeline from Figma source to multi-platform outputs with CI validationA design token flows from Figma through Token Studio to a Git repository, gets validated by CI checks for schema, contrast, and visual regression, then Style Dictionary generates CSS, iOS, Android, and React Native outputs that are published as versioned packagesDesign Token PipelineFrom Figma to every platform in one commitFigmaToken Studio pluginedits token valuesSyncs to Git on savetokens.jsonGit repositoryPR opened on changeSingle source of truthSchematype, value, descContrastWCAG AA 4.5:1Visual DiffChromatic/PercyStyle DictionaryParse tokens + custom transformsrem, dp, CGFloat, px conversionsCSS Custom Props--color-primary: #1A2980iOS SwiftUIColor(r:0.1, g:0.16, b:0.5)Android XMLcolor/primary = #1A2980React Nativecolors.primary = '#1A2980'Versioned Packages Published to Internal Registryv2.4.1 - Consuming apps pin to version, upgrade explicitlyToken LayersGlobalblue-500: #1A2980Aliascolor-interactive -> blue-500Theme SwitchingLightDarkSame components, different token values

Theme Switching Architecture

background: white hardcoded in 200 components needs 200 changes for dark mode. background: var(--color-surface) needs one. A data-theme attribute on the root switches values.

Theme Switching: One Attribute, Every Token ResolvesTheme Switching: One Attribute, Every Token Resolvesdata-theme="light"--color-surface: white--color-text: gray-900User Toggles ThemeJavaScript sets data-theme="dark"CSS custom properties swap instantlydata-theme="dark"--color-surface: gray-900--color-text: whiteSame semantic tokens. Different values per theme. Zero component code changes.

Check localStorage first, fall back to prefers-color-scheme, store the user’s toggle. Fix the flash of wrong theme (FOWT) with a blocking inline <script> in <head> that sets data-theme before CSS renders.

The Dark Mode Tax

Shadows disappear on dark backgrounds. You need elevated surface tokens (surface-elevated-1, -2, -3). Images need treatment. Screenshots on light UI look jarring on dark. Contrast ratios shift. Text passing AA on white often fails on dark gray. Every token pair needs verification per theme.

Total effort routinely exceeds the initial estimate by a wide margin. The token architecture contains it to the token layer instead of spreading across every component. Effective design system architecture treats dark mode as day-one infrastructure.

Dark mode token mapping checklist
  • Surface hierarchy: Define surface-1, surface-2, surface-3 for light and dark. In dark mode, elevated surfaces are lighter, not darker. Shadows lose their visual effect on dark backgrounds, so surface elevation replaces shadow depth.
  • Text contrast: Every text-on-surface combination needs WCAG AA verification per theme. Pure white (#FFFFFF) text on dark backgrounds causes eye strain. Use #E0E0E0 or lighter grays.
  • Image treatment: Add a subtle overlay or reduced brightness to screenshots and illustrations that assume a light background. SVG icons should reference token colors, not hardcoded values.
  • Accent colors: Saturated colors that pass contrast on white often fail on dark gray. Maintain a parallel set of accent tokens with adjusted lightness values per theme.
  • Borders and dividers: 1px solid #E0E0E0 vanishes on a dark surface. Divider tokens need separate light and dark mappings.

Token Versioning and Breaking Changes

Tokens are an API. Rename color-primary to color-brand-primary and every consumer breaks. Semantic versioning: new tokens are minor, value changes are patches, renames/deletions are major.

CI should diff against the last published version and classify each change. Block the merge until the version bump matches the severity. Without this, a designer renames in Figma, sync pushes to Git, and three apps break.

Token Versioning: CI Detects Breaking ChangesToken Versioning: CI Detects Breaking ChangesToken PRDesigner changescolor-primary valueCI Diff AnalyzerCompare old vs new tokensClassify: patch / minor / majorToken removed = breakingNon-breaking: auto-publishBreaking: require migrationConsumers notifiedToken changes are design system deploys. Semver and CI gates apply.

CI Pipelines for Token Validation

Three CI stages: schema validation (type, value, description required), contrast verification (every foreground-background pair checked per theme against WCAG AA), and visual regression (Chromatic/Percy on Storybook). 45-90 seconds of build time versus hours of production debugging. CI/CD pipelines make this trivial.

The Handoff Gap

Token Studio makes Figma and Git share the same source. Designer changes a token, plugin opens a PR, CI validates, engineer merges. The “Figma vs. code is the source of truth” debate dies. The token JSON file is the source. Neither side can drift.

Chromatic’s visual diff catches changes that are numerically correct but look wrong in context. Building web applications at scale requires this design-to-code automation.

When Tokens Become Tech Debt

When tokens add valueWhen tokens add overhead
Multiple platforms consuming the same visual languageSingle-platform product with no mobile roadmap
More than 2 teams building UI against the same design systemSolo developer or small team with direct Figma-to-code workflow
Dark mode, theming, or multi-brand requirements exist or are plannedSingle theme with no foreseeable need for variation
Design and engineering teams are separate and need a shared contractDesigner-developer working as a pair on every component

Three rot signals to watch for:

Token explosion past 2,000 where developers create tokens instead of discovering existing ones. Fix with enforced naming conventions and a searchable token catalog. Orphan tokens referenced by zero apps. Run a quarterly audit against actual usage and deprecate aggressively. Alias bypass where components reference globals directly (--blue-500 instead of --color-interactive). Lint rules catch this automatically.

Anti-pattern

Don’t: Reference global tokens directly in component CSS: background: var(--blue-500). When you need dark mode or a second brand, every component needs rewriting.

Do: Reference alias tokens: background: var(--color-interactive). Theme switching changes the alias mapping. Components never know the difference.

The Token Drift Window The time between a design change in Figma and that change reaching every platform’s production code. Without an automated pipeline, this window is measured in sprints. With one, it’s measured in minutes.

What the Industry Gets Wrong About Design Tokens

“CSS variables are design tokens.” CSS variables are one output format. Tokens are the source definition plus the pipeline that generates outputs for every platform. A team maintaining CSS variables manually in a stylesheet has CSS variables, not design tokens.

“Dark mode is just inverting colors.” Dark mode requires a separate set of alias token mappings that account for contrast, perceived brightness, and elevation hierarchy. A simple inversion produces text that’s too bright, surfaces that lack depth, and contrast ratios that fail WCAG. Proper dark mode is a full design exercise expressed through the token layer.

Our take Skip component tokens initially. Global and alias tokens deliver the bulk of the value. Component tokens add precision but also maintenance burden. Add them when you have more than 3 teams consuming the token library and variant-level control becomes necessary. Before that point, alias tokens handle the abstraction cleanly enough.

The design systems engineering guide covers component architecture on top of the token layer. Treat tokens like any other shared dependency: versioned, tested, distributed through packages, monitored for drift. Otherwise: four platforms, four different blues, zero coordination.

Ship Consistent UI Without the Coordination Tax

The real cost of visual inconsistency isn’t pixels out of place. It’s the engineering time debugging why the same blue renders differently on three platforms. Token pipelines transforming a single source of truth into CSS, iOS, Android, and React Native outputs, with CI validation on every commit.

Unify Your Design Tokens

Frequently Asked Questions

What is the difference between a design token and a CSS variable?

+

A design token is a platform-agnostic design decision stored in JSON or YAML. A CSS variable is one output format. Style Dictionary transforms a single token file into CSS custom properties, Swift UIColor constants, Android XML resources, and React Native style objects. Changing a primary color in the token source propagates to every platform in one commit. Teams using structured tokens see cross-platform style drift nearly vanish within six months.

How many tokens does a typical design system need?

+

A mature system contains 200-400 global tokens (colors, spacing, typography, elevation, motion) and 500-1,500 component-level tokens that reference them through aliases. Start with 80-100 global tokens covering your color palette, spacing scale, and type ramp. Add component tokens incrementally as you build. Teams that pre-define 1,000+ tokens before building components waste a large share of them because actual usage patterns diverge from the predicted ones.

How do you handle breaking changes in token values?

+

Treat token renames and deletions like API breaking changes. Run a CI job that compares the current token file against the previous release, flags any removed or renamed keys, and blocks the merge until the change is documented in a changelog. Value changes to existing tokens (shifting a blue 2 degrees) are non-breaking. Renaming color-primary to color-brand-primary breaks every consumer. Semantic versioning applies: value tweaks are patches, new tokens are minor, renames or deletions are major.

Does dark mode double the CSS bundle size?

+

Naive implementations double it. A token-driven approach adds 2-4 KB of CSS. The light and dark themes share the same component styles. Only the token values change via CSS custom properties toggled by a data attribute or media query. A well-structured system defines roughly 80-120 semantic color tokens. Swapping those values adds one extra declaration block per token, not a duplicate of every component rule.

What is the recommended CI pipeline for design token validation?

+

Run three checks on every pull request: schema validation (ensure all tokens have required fields like type, value, and description), contrast ratio verification (flag any foreground-background token pair below WCAG AA 4.5:1), and a visual diff using Chromatic or Percy on Storybook stories that consume the changed tokens. This pipeline catches most visual regressions before they reach staging. Build time adds roughly 45-90 seconds.