Tokens & context

Foundations are the value layer of a system: typed tokens, arranged in layers, able to answer differently per context. Every facet in every component points at one of them, which is what makes a restyle a change in foundations rather than a sweep through components.

#Tokens are typed

A token is a name, a type and a value. The type is a closed word, and it decides what the value means: 1.5 is a ratio for a ratio token and an error for a spacing one, which needs a unit. The types:

  • Colour: color, gradient.
  • Length: spacing, radius, size, border, font-size, letter-spacing. Written with px, a density-independent unit, or scaled(n) for a length relative to the reader's text size.
  • Type: font-family (a record: family, fallback, source, licence), typography (a text style record), font-weight, ratio (a line height).
  • Motion: duration, easing.
  • Depth and layering: shadow, elevation, tonal, ring, backdrop, blur, opacity.

The literals each type accepts are on Values & literals. In the Studio every type has an editor built around what the type is: a radius is shown on a box, a duration as frames to replay, an elevation as a light direction.

#Tokens are layered

A layer is a named group of tokens in reading order. The convention is three: Base holds the literals, Semantic holds roles that alias them, and a Component layer may alias those again for one component's needs. Resolution chains downward by substitution.

milda
context-group ColorScheme { Light Dark }
context-group Density { Compact Comfortable }

foundations {
  layer Base {
    token violet/600 : color = hex(7c3aed)
    token violet/500 : color = hex(8b5cf6)
    token space/2 : spacing = 8px
    token space/3 : spacing = 12px
  }
  layer Semantic {
    token accent : color = alias by ColorScheme { default -> violet.600; Dark -> violet.500 }
    token gap/control : spacing = alias by Density { default -> space.3; Compact -> space.2 }
  }
  layer Component {
    token button/fill : color = alias by ColorScheme { default -> accent }
  }
}

Components reference the top of the chain: fill button.fill. Change accent and the fill follows; change violet/600 and both follow.

#Context is a dimension

A context group is a dimension a token can answer differently along: colour scheme, density, platform, brand, breakpoint. Its members are contexts. A token answers per context with an alias by block, and default is the fallback for every context the block does not name.

Several active dimensions resolve by chaining: in the file above, button.fill aliases by scheme and points at accent, which aliases by scheme again, while a spacing aliases by density alone. There is never a composite key like dark+compact, which would multiply with every dimension added. Platform is a context group like any other, and the outermost one when it exists: it picks the mechanism, the scheme picks the value.

milda
context-group Platform { Web iOS Android }

foundations {
  token shadow/lg : shadow = raw "0 10px 15px rgba(0,0,0,.1)"
  token tonal/3 : tonal = 3
  token elevation/overlay : elevation = alias by Platform { Web -> shadow.lg; Android -> tonal.3; iOS -> none; default -> shadow.lg }
}

component Popover {
  archetype Popover
  part Popover: container {
  }
  part surface: container {
    elevation elevation.overlay
  }
}

That is the whole of per-platform styling. elevation is an abstract facet type whose alias may point at tokens of different concrete types per platform (a shadow on the web, a tonal step on Android, nothing on iOS), and the component says elevation elevation.overlay once. There is no per-platform style block in the language.

#A prop can be a dimension

A context group's value can come from a prop instead of the environment. A prop typed by a group (variant : context Variant, or just variant : Variant) takes the group's contexts as its values and, when set, shadows the ambient context for that component's subtree. That single rule is what variant, size, a per-instance accent and responsive props all are: token aliasing with the dimension's value supplied per instance. Resolution precedence: the prop on the nearest instance, then the ambient value, then the group's default.

A prop the whole system shares, such as a control size, is declared once as a and taken with global size, so every component agrees on its name, type and default:

milda
context-group Size { Small Medium Large }

foundations {
  token space/1 : spacing = 4px
  token space/2 : spacing = 8px
  token space/3 : spacing = 12px
  token control/inset : spacing = alias by Size { Small -> space.1; Medium -> space.2; Large -> space.3; default -> space.2 }
}

global-prop size : Size = Medium "The control size, shared by every input."

component Button {
  archetype Button
  props {
    global size
    label : string = "Save"
  }
  part Button: container {
    inset control.inset
  }
  part label: text {
    content bind label
  }
}

#Computed and composite values

A token can be derived from another, live: compute accent in oklch { darken 10% }. The steps a token accepts follow its type (lighten, darken, mix, alpha and rotate for colours; scale, offset and round for lengths), so a colour step on a length is an error rather than a no-op. A text style and a font family are records, edited as a unit; their shape is on Values & literals.

#What the targets do with them

  • React emits a theme.css of custom properties, one per token, with a block per context ([data-color-scheme="dark"]) that re-points the aliased ones. Components reference the properties, so a theme change reaches them without regeneration.
  • Figma emits Variables with a mode per context, and a W3C DTCG token file.

Which of these a project produces is its choice of targets, kept beside the document.

Built

New projects import tokens from DTCG, Tokens Studio, Style Dictionary, Tailwind and Figma exports; every path converts to .milda text first.

These words, in the reference

  • A dimension a token can answer differently along: colour scheme, density, platform, brand.
  • The design tokens.
  • A named layer of tokens, such as primitives and then the semantic tokens that alias them.
  • Declares a design token.
  • A token whose value depends on a context.
  • A value derived from another one, live: "the accent, 20% lighter".

Open a word for its entry, or read them all in the reference.

See it built in the tour2. Layers and context10. Type, motion and computed values