Lesson 2 of 14
Layers and context
Base tokens hold the literals; semantic tokens alias them, per colour scheme.
#The idea
Components will never paint with violet/600 directly. They paint with roles: the accent, the surface, the text colour. Roles live in a second layer that points at the first, and a role can point somewhere different per context, so a dark scheme is a second set of arrows rather than a second system.
#What this lesson adds
A context group, then two layers of tokens:
context-group ColorScheme { Light Dark }
token accent : color = alias by ColorScheme { default -> violet.600; Dark -> violet.500 } token accent-hover : color = alias by ColorScheme { default -> violet.700; Dark -> violet.600 } token accent-subtle : color = alias by ColorScheme { default -> violet.100; Dark -> violet.900 } token on-accent : color = alias by ColorScheme { default -> white } token surface : color = alias by ColorScheme { default -> white; Dark -> gray.900 } token text : color = alias by ColorScheme { default -> gray.900; Dark -> gray.50 } token text-muted : color = alias by ColorScheme { default -> gray.500 } token line : color = alias by ColorScheme { default -> gray.200; Dark -> gray.800 } token success : color = alias by ColorScheme { default -> green.500 } token warning : color = alias by ColorScheme { default -> amber.500 }
#What to notice
- A layer is reading order.
layer Baseholds the literals;layer Semanticholds roles that alias them. Resolution walks down:accentasksviolet.600, which is a literal, and stops. - A context group is a dimension.
ColorSchemehas two contexts, andalias by ColorScheme { default -> violet.600; Dark -> violet.500 }answers per context. is the fallback for every context the alias does not name, soLightnever has to be spelled out. - Dimensions chain, they do not multiply. Add a
Densitygroup later and a spacing token aliases by it; a colour token still aliases by scheme alone. Two dimensions never become a dark+compact key anywhere. - Not only colours. The same layer holds spacing, radii, a border width and type sizes. is a radius that fully rounds the shorter side: an intent, not a large number.
#What the generator makes of it
The theme now has a block per context: :root carries the defaults, and [data-color-scheme="dark"] re-points every token that answers differently in the dark. Switching an app to dark is setting one attribute on an ancestor.
#Try it
Switch the Playground's preview to dark and open the accent token: the panel shows which arrow is live. Then give on-accent a Dark slot pointing at gray.900 and watch what changes and what does not.
Words in this lesson
- A dimension a token can answer differently along: colour scheme, density, platform, brand.
- A named layer of tokens, such as primitives and then the semantic tokens that alias them.
- A token whose value depends on a context.
Open a word for its entry, or read them all in the reference.
#The file at the end of this lesson
milda 0.10 prelude 0.0.2 meta { name "Acme" } context-group ColorScheme { Light Dark } foundations { layer Base { token violet/100 : color = hex(ede9fe) token violet/500 : color = hex(8b5cf6) token violet/600 : color = hex(7c3aed) token violet/700 : color = hex(6d28d9) token violet/900 : color = hex(4c1d95) token gray/50 : color = hex(f8fafc) token gray/200 : color = hex(e2e8f0) token gray/500 : color = hex(64748b) token gray/800 : color = hex(1e293b) token gray/900 : color = hex(0f172a) token green/500 : color = hex(22c55e) token amber/500 : color = hex(f59e0b) token white : color = hex(ffffff) } layer Semantic { token accent : color = alias by ColorScheme { default -> violet.600; Dark -> violet.500 } token accent-hover : color = alias by ColorScheme { default -> violet.700; Dark -> violet.600 } token accent-subtle : color = alias by ColorScheme { default -> violet.100; Dark -> violet.900 } token on-accent : color = alias by ColorScheme { default -> white } token surface : color = alias by ColorScheme { default -> white; Dark -> gray.900 } token text : color = alias by ColorScheme { default -> gray.900; Dark -> gray.50 } token text-muted : color = alias by ColorScheme { default -> gray.500 } token line : color = alias by ColorScheme { default -> gray.200; Dark -> gray.800 } token success : color = alias by ColorScheme { default -> green.500 } token warning : color = alias by ColorScheme { default -> amber.500 } token space/xs : spacing = 4px token space/sm : spacing = 8px token space/md : spacing = 12px token space/lg : spacing = 16px token space/xl : spacing = 24px token radius/sm : radius = 6px token radius/lg : radius = 12px token radius/pill : radius = pill token hairline : border = 1px token size/sm : font-size = 13px token size/md : font-size = 15px token size/lg : font-size = 18px token weight/medium : font-weight = 500 token weight/bold : font-weight = 700 } }