Modes
How Resolver axes build the theme×brand×density mode space.
Modes are first-class graph selectors
Facet mode structure lives in a *.resolver.json file.
{
"sets": {
"core": "palette.facet.json",
"theme.light": "themes/light.facet.json",
"theme.dark": "themes/dark.facet.json",
"brand.acme": "brands/acme.facet.json"
},
"modifiers": {
"theme": { "values": ["light", "dark"], "default": "light", "selector": { "light": ":root", "dark": ".dark" } },
"brand": { "values": ["acme"], "default": "acme", "selector": { "acme": ":root" } }
},
"apply": [
{ "always": ["core"] },
{ "when": { "theme": "light" }, "use": ["theme.light"] },
{ "when": { "theme": "dark" }, "use": ["theme.dark"] },
{ "when": { "brand": "acme" }, "use": ["brand.acme"] }
]
}
What the resolver does
sets: named token filesmodifiers: orthogonal axes with declared values and selectorsapply: selects which sets participate for a given coordinate
A coordinate is a single value for each axis (for example theme=dark, brand=globex).
All coordinates are the Cartesian product of modifier values.
Layered emission
Build emits:
- base layer for the all-defaults coordinate (
:root) - override layers only for tokens that change under non-default axis values
This keeps mode switching cheap because variables switch by selector and atoms do not recompile.
Runtime mode toggles (no re-render required)
In the reference demo, modes are toggled through selectors:
document.documentElement.classList.toggle('dark');
document.documentElement.dataset.brand = 'globex';
document.documentElement.dataset.density = document.documentElement.dataset.density === 'compact' ? '' : 'compact';
document.documentElement.dir = document.documentElement.dir === 'rtl' ? 'ltr' : 'rtl';
Multi-axis example from source
The checked-in resolver includes theme, brand, and density with values:
theme:light,darkbrand:acme,globex,verdantdensity:comfortable,compact
That creates 12 permutations.
Planned status
- The resolver mapping aligns to the DTCG resolver draft.
- Cross-axis combination support is implemented as layered defaults + diffs; full Resolver-module stability is noted as draft in source docs.