Skip to content

Theming with Modifiers

The resolver’s modifier system enables theming without token duplication. Define base tokens once, then overlay context-specific overrides for themes, densities, and brands.

  1. Create a resolver with a theme modifier (light/dark contexts)
  2. Define base tokens with raw color values
  3. Define theme tokens as semantic aliases that switch per theme
{
"version": "2025.10",
"sets": {
"base": { "sources": [{ "$ref": "./tokens/base.json" }] },
"alias": { "sources": [{ "$ref": "./tokens/semantic.json" }] }
},
"modifiers": {
"theme": {
"default": "light",
"contexts": {
"light": [{ "$ref": "./tokens/themes/light.json" }],
"dark": [{ "$ref": "./tokens/themes/dark.json" }]
}
}
},
"resolutionOrder": [
{ "$ref": "#/sets/base" },
{ "$ref": "#/modifiers/theme" },
{ "$ref": "#/sets/alias" }
]
}

Multi-Dimensional Theming: Theme × Density

Section titled “Multi-Dimensional Theming: Theme × Density”

Use multiple modifiers for theme × density (or theme × brand):

  • Resolver with theme and density modifiers
  • Resolution order: base → density → theme → semantic

Each permutation (e.g. light+compact, dark+comfortable) produces a complete token set.

Use a dynamic selector function so the base maps to :root and each modifier maps to a data attribute:

css({
name: 'themed',
file: 'tokens.css',
preset: 'bundle',
selector: (modifierName, context, isBase, allModifierInputs) => {
if (isBase) return ':root'
return `[data-${modifierName}="${context}"]`
},
})

Output:

:root { --color-background: #ffffff; }
[data-theme="dark"] { --color-background: #111111; }
[data-density="compact"] { --spacing-medium: 12px; }

CSS with Media Query for prefers-color-scheme

Section titled “CSS with Media Query for prefers-color-scheme”

Use mediaQuery to have dark theme apply automatically when the user prefers dark mode:

css({
name: 'auto-theme',
file: 'tokens.css',
preset: 'bundle',
mediaQuery: (modifierName, context, isBase, allModifierInputs) => {
if (modifierName === 'theme' && context === 'dark') {
return '(prefers-color-scheme: dark)'
}
return ''
},
})

For platform-specific builds, use the standalone preset with dynamic file patterns:

  • JSON: file: 'tokens-{theme}.json'tokens-light.json, tokens-dark.json
  • Swift: file: 'DesignTokens-{theme}.swift'
  • Kotlin: file: 'DesignTokens-{theme}.kt'

Use preset: 'modifier' to output only tokens that differ between base and each modifier. Useful for overlay/patch files that layer on top of a base stylesheet.