Skip to main content

Token Contract for Components

Premise

When a system engineer builds a component — or when a product engineer customizes a screen — they need to know exactly which tokens to use, where they come from, and what the engine guarantees will never change without notice. This document defines that contract: the canonical rules governing token consumption in components and UIs.

The contract has two dimensions:

  • Which tokens to use (Semantic vs Foundation, when and why)
  • What the engine guarantees (reserved namespaces, breaking changes, versioning)

The Fundamental Rule

Always use Semantic.
Use Foundation when a suitable alias exists.
Never use Brand, Mode, or Surface directly.
LayerConsumption in componentsWhy
SemanticAlways — it is the canonical exposed layerExpresses purpose, not internal value. All tokens are calculated, tested, and WCAG-guaranteed
FoundationWhen a suitable alias already existsCognitive shortcut for product teams. Does NOT replace Semantic as the source of truth
brand.*, mode.*, surface.*Prohibited in component codeInternal layers — any reference to them breaks with architecture changes

Why Semantic, not Foundation?

Foundation is a cognitive load-reduction layer — it exists for product teams building screens, not for those building the components themselves. A component using foundation.bg.primary apparently works, but depends on the current theme having that alias defined. If the alias does not exist or changes, the component breaks silently.

Semantic is the stable contract. A Foundation alias is optional and convenient — never mandatory.


Who Consumes What

ProfilePrimary layerFallback
DS Engineer (builds base components)Semantic — always, no exceptions
Product Engineer (assembles screens with components)Foundation — when the alias existsSemantic when the alias does not cover the case
Designer (in Figma via Tokens Studio)Semantic — for components; Foundation — for layouts
AI / Code ConnectSemantic identified by semantic.*Foundation identified by foundation.*

How to Identify Tokens

The path prefix identifies the layer:

PrefixLayerExample
semantic.*Semantic — canonical layersemantic.color.interface.function.primary.normal.background
foundation.*Foundation — alias for Semanticfoundation.bg.primary
component.*Component — component-specific tokens (when available)component.button.primary.background
brand.*, mode.*, surface.*Internal layers — never use

In CSS, the same prefixes are used with hyphens:

/* Semantic */
var(--semantic-color-interface-function-primary-normal-background)

/* Foundation */
var(--foundation-bg-primary)

Semantic Token Map by Category

Brand Colors — semantic.color.brand

Branding (semantic.color.brand.branding)

Primary brand identity. Use in hero areas, brand CTAs, and highlights.

Structure: semantic.color.brand.branding.{role}.{intensity}.{property}

SegmentValues
{role}first, second, third
{intensity}lowest, low, default, high, highest
{property}background, txtOn, border, txt (since 3.6.0)
/* Brand hero button, normal state */
background: var(--semantic-color-brand-branding-first-default-background);
color: var(--semantic-color-brand-branding-first-default-txt-on);
border: var(--semantic-color-brand-branding-first-default-border);

Ambient (semantic.color.brand.ambient)

Base canvas, neutrals, and grayscale. Use in layout, surfaces, and text hierarchy — not in colorful emphasis.

Structure:

SubgroupKeysTypical use
contrast.basepositive, negativeMain canvas, surface contrast
contrast.deeppositive, negativeAbsolute light and dark
neutrallowesthighest (7 levels)Elevated panels, secondary surfaces
grayscalelowesthighest (7 levels)Fixed grayscale independent of brand
/* Main canvas background */
background: var(--semantic-color-brand-ambient-contrast-deep-positive-background);

/* Elevated panel */
background: var(--semantic-color-brand-ambient-neutral-low-background);

Interactive Controls — semantic.color.interface.function

Buttons, links, controls, and interactive elements.

Structure: semantic.color.interface.function.{role}.{state}.{property}

{role}Use
primaryMain CTA
secondarySecondary action
linkLinks and text actions
activeActive or selected UI
disabledDisabled controls (only has normal state)
{state}Maps to
normalDefault / resting state
actionHover or pressed
activeActive / selected
/* Primary button — normal */
background: var(--semantic-color-interface-function-primary-normal-background);
color: var(--semantic-color-interface-function-primary-normal-txt-on);
border: var(--semantic-color-interface-function-primary-normal-border);

/* Primary button — hover */
background: var(--semantic-color-interface-function-primary-action-background);

/* Disabled button */
background: var(--semantic-color-interface-function-disabled-normal-background);
color: var(--semantic-color-interface-function-disabled-normal-txt-on);

System Feedback — semantic.color.interface.feedback

Alerts, badges, and system messages: info, success, warning, danger.

Structure: semantic.color.interface.feedback.{type}.{variant}.{state}.{property}

{type}Meaning
infoInformational / neutral
successConfirmation / success
warningAttention / alert
dangerError / destructive action
{variant}Use
defaultSoft background — alert surfaces
secondaryMore saturated variant — borders and icons
/* Success alert */
background: var(--semantic-color-interface-feedback-success-default-normal-background);
color: var(--semantic-color-interface-feedback-success-default-normal-txt-on);
border: var(--semantic-color-interface-feedback-success-secondary-normal-border);

Accessibility rule: Always use background and txtOn from the same token. The pair guarantees WCAG contrast. Never combine a background from one level with a txtOn from another.


Text Colors — semantic.color.text

Simplified text tokens — flat, without intensity, purpose only.

TokenUse
semantic.color.text.titleTitles and primary UI text
semantic.color.text.bodyBody text — main content
semantic.color.text.highlightHighlighted or emphasized text
semantic.color.text.mutedSecondary or disabled text
semantic.color.text.labelForm labels and captions
semantic.color.text.info_defaultInformational feedback text
semantic.color.text.success_defaultSuccess feedback text
semantic.color.text.warning_defaultWarning text
semantic.color.text.danger_defaultError text
h1 { color: var(--semantic-color-text-title); }
p { color: var(--semantic-color-text-body); }
label { color: var(--semantic-color-text-label); }

Product Colors — semantic.color.product

Product-specific colors — promotions, cashback, tiers, categorizations. The only open area of Semantic where product teams can declare custom categories.

Structure: semantic.color.product.{item}.{variant}.{intensity}.{property}

SegmentValues
{item}promo, cashback, premium — or any free name defined in the config
{variant}default, secondary
{intensity}lowest, low, default, high, highest
{property}background, txtOn, border, txt (since 3.6.0)

Plain text tokens also available at semantic.color.text.{item} and semantic.color.text.{item}_secondary.

[!CAUTION] Exponential cost. Each new item in product generates at minimum 40 tokens (since 3.6.0) that propagate through all layers and all themes. In a system with 4 themes, a single item represents +160 tokens. Before adding, ask: "Can this be resolved with existing feedback or brand tokens?" See 04-semantic-layer.md for the full rationale.


Gradients — semantic.color.gradient

Configuration and steps for brand gradients.

GroupTokens
gradient.config.degreeshorizontal, vertical, toBottom, diagonalLeft, diagonalRight, diagonalBrand, diagonalBrandAlt
gradient.config.steps0, 10, 20, … 100 (stops in %)
gradient.config.colorsfirst.lowest, first.default, etc.

Gradients are configured in the theme file (*.config.mjs) and only appear in the output if sync:architecture runs after themes:generate. See 04-build-pipeline.md.


Opacity — semantic.opacity

Transparency for overlays, disabled states, and glass effects.

SubgroupKeysUse
opacity.rawtransparent (0), superTransparent (10), semiTranslucid (20), translucid (50), superTranslucid (80), semiOpaque (90), opaque (100)Numeric value to apply to any color
opacity.color.grayscaleSame keysDark color with opacity already applied
opacity.color.lightSame keysLight color with opacity already applied
/* Modal overlay */
background: var(--semantic-opacity-color-grayscale-super-translucid);

/* Disabled state via opacity */
opacity: calc(var(--semantic-opacity-raw-semi-translucid) / 100);

Typography — semantic.typography

Structure:

GroupRelevant tokens
fontFamiliesmain, content, display, code
fontWeightsBy family × weight × style (normal/italic)
fontSizesextraSmallpeta (scale of 13 sizes)
lineHeightstight, close, regular × size
letterSpacings, paragraphSpacing, textCase, textDecorationTypographic complements

Foundation composite styles (heading, content, display, hierarchy, action, link, code) consume these tokens and are the preferred form for product teams. In the DS, access semantic.typography directly for granular control.


Dimension — semantic.dimension

Spacing and sizing for layout, padding, margin, gap, and component dimensions.

GroupToken scale
sizingzero, pico, nano, micro, extraSmall, small, medium, large, extraLarge, mega, giga, tera, peta
spacingSame scale (minimum: micro)

medium in the normal variant corresponds to 16px (1 LayoutUnit). Use sizing for component height, icon, and border thickness; spacing for padding, margin, and gap.


Border — semantic.border

GroupTokensUse
widthnone, small, medium, large, extraLargeOutline thickness, dividers, focus rings
radiistraight, micro, extraSmall, small, medium, large, extraLarge, mega, circularBorder radius by component
/* Card with medium radius */
border-radius: var(--semantic-border-radii-medium);
border-width: var(--semantic-border-width-small);

Depth — semantic.depth

Shadow spread for elevation.

TokenValueUse
depth.spread.close0No elevation
depth.spread.next-2Minimum elevation
depth.spread.near-4Cards and panels
depth.spread.distant-8Dropdowns
depth.spread.far-12Modals and dialogs

Higher magnitude = more elevation. Foundation composite elevation styles (elevation.level_oneelevation.level_five) are the preferred form for product teams.


The Background + txtOn Pair

Every colored surface in the system has two complementary tokens: background and txtOn. The txtOn is automatically calculated by the engine to guarantee WCAG AA contrast (or AAA, depending on the theme config).

Invariable rule: Always use the txtOn from the same token as the background.

/* CORRECT — pair from the same token */
.badge-success {
background: var(--semantic-color-interface-feedback-success-default-normal-background);
color: var(--semantic-color-interface-feedback-success-default-normal-txt-on);
}

/* WRONG — mixing different tokens */
.badge-success {
background: var(--semantic-color-interface-feedback-success-default-normal-background);
color: var(--semantic-color-text-body); /* ← contrast not guaranteed */
}

Forbidden Patterns

Forbidden patternWhyWhat to use instead
var(--theme-color-*)Internal layervar(--semantic-color-*)
var(--brand-*), var(--mode-*), var(--surface-*)Internal layersvar(--semantic-color-*)
Inventing --semantic-color-my-color in product CSSViolates the contract — may conflict with future buildsUse only paths that exist in dist/
Hardcoded hex #C40145 in component CSSLoses automatic theming, dark mode, and multi-brandvar(--semantic-color-interface-function-primary-normal-background)
semantic.color.interface.feedback.info_default.background with semantic.color.text.body overlaidContrast not guaranteedUse the background + txtOn pair from the same token

Versioning Contract

What is guaranteed

The engine guarantees that published paths in dist/ (e.g., --semantic-color-interface-function-primary-normal-background) will not change without a major version bump. Any path that appears in the build is part of the public contract.

What is a breaking change

  • Renaming a token path (semantic.color.interface.oldNamesemantic.color.interface.newName) — major version
  • Removing a token path — major version
  • Adding a new path — minor version (does not break existing consumers)

Deprecation

When a token needs to be renamed, the engine may opt for a deprecation window: the old path remains in the build marked as deprecated in $description, with the new path indicated. Removal happens in the next major version.

Changes are documented in the engine's CHANGELOG.md, which specifies: old path, new path, removal version.


References