- From: lab9 via GitHub <noreply@w3.org>
- Date: Wed, 14 Jan 2026 07:46:42 +0000
- To: public-design-tokens-log@w3.org
lab9fr has just created a new issue for https://github.com/design-tokens/community-group:
== How to model a true 2-dimensional modifier (brand × theme) ==
### Before starting
- [x] I have searched [existing issues](https://github.com/design-tokens/community-group/issues) and there is not already an open issue on the subject.
### Summary
Hello Everyone,
I’m trying to model a common design-system scenario using the W3C Design Tokens **Resolver** specification: combining a **theme modifier** (light / dark) with a **brand modifier** (red / blue) so that a single semantic token (e.g. `semantic.color.primary`) resolves to one of four values.
Because modifiers are not allowed to reference other modifiers, I’ve implemented this by having the **theme modifier define the full light/dark structure**, including brand-specific slots (`red` and `blue`), and then using the **brand modifier to select the appropriate branch** of that structure.
The goal of this issue is to confirm whether this pattern is the **intended and recommended way** to model multi-dimensional concerns (like theme and brand) with the resolver, or whether there are other approaches supported or envisioned by the specification.
### Version
Third Editor’s Draft
### Problem & motivation
The Resolver specification states:
> **“A modifier MAY reference a set inside a context value.
> However a modifier MUST NOT reference any other modifier,
> not even another context inside the same modifier.”**
I’m trying to stay strictly within this rule while modeling a common design-system case: combining **theme** (light/dark) and **brand** (red/blue) to resolve a single semantic color.
## Resolver setup
I have two independent modifiers:
* **theme**: `light | dark`
* **brand**: `red | blue`
They are composed using `resolutionOrder`, without any modifier referencing another modifier.
```json
// tokens.resolver.json
// Goal: compose theme (light/dark) and brand (red/blue)
{
"$schema": "https://www.designtokens.org/schemas/2025.10/resolver.json",
"version": "2025.10",
"sets": {
"color": {
"sources": [
{ "$ref": "base.json" },
{ "$ref": "semantic.json" }
]
}
},
"modifiers": {
"theme": {
"description": "Color Theme",
"contexts": {
"light": [{ "$ref": "theme/light.json" }],
"dark": [{ "$ref": "theme/dark.json" }]
},
"default": "light"
},
"brand": {
"description": "Brand",
"contexts": {
"red": [{ "$ref": "red.json" }],
"blue": [{ "$ref": "blue.json" }]
},
"default": "red"
}
},
"resolutionOrder": [
{ "$ref": "#/sets/color" },
{ "$ref": "#/modifiers/theme" },
{ "$ref": "#/modifiers/brand" }
]
}
```
**Intent:**
Choosing `{ theme, brand }` should result in one of four values:
* red–light
* red–dark
* blue–light
* blue–dark
## Base colors
These are simple primitives, independent of both theme and brand.
```json
// base.json
{
"$schema": "https://www.w3.org/TR/design-tokens/",
"ns": {
"base": {
"color": {
"red": {
"1": { "$type": "color", "$value": "#ff0000" },
"2": { "$type": "color", "$value": "#800000" }
},
"blue": {
"1": { "$type": "color", "$value": "#0000ff" },
"2": { "$type": "color", "$value": "#000080" }
}
}
}
}
}
```
## Semantic token
This is the token consumers use.
It’s expected to resolve differently depending on theme and brand.
```json
// semantic.json
{
"$schema": "https://www.w3.org/TR/design-tokens/",
"ns": {
"semantic": {
"color": {
"primary": {
"$type": "color",
"$value": "{ns.theme.primary}"
}
}
}
}
}
```
## Theme modifier sources
In this model, **themes own the light/dark logic and expose brand slots**.
Each theme defines how red and blue should look in that theme.
```json
// theme/light.json
// Light theme defines light versions of each brand color
{
"$schema": "https://www.w3.org/TR/design-tokens/",
"ns": {
"theme": {
"primary": {
"red": {
"$type": "color",
"$value": "{ns.base.color.red.1}"
},
"blue": {
"$type": "color",
"$value": "{ns.base.color.blue.1}"
}
}
}
}
}
```
```json
// theme/dark.json
// Dark theme defines dark versions of each brand color
{
"$schema": "https://www.w3.org/TR/design-tokens/",
"ns": {
"theme": {
"primary": {
"red": {
"$type": "color",
"$value": "{ns.base.color.red.2}"
},
"blue": {
"$type": "color",
"$value": "{ns.base.color.blue.2}"
}
}
}
}
}
```
At this stage, the theme defines *what “primary” means* for each brand color.
## Brand modifier sources
The brand modifier now simply selects which branch of the theme structure to use and extends the semantic intent.
```json
// red.json
// Brand = red
{
"$schema": "https://www.w3.org/TR/design-tokens/",
"ns": {
"semantic": {
"color": {
"primary": {
"$type": "color",
"$value": "{ns.theme.primary.red}"
}
}
}
}
}
```
```json
// blue.json
// Brand = blue
{
"$schema": "https://www.w3.org/TR/design-tokens/",
"ns": {
"semantic": {
"color": {
"primary": {
"$type": "color",
"$value": "{ns.theme.primary.blue}"
}
}
}
}
}
```
Here, the brand modifier does **not** reference the theme modifier itself — only token paths that already exist after theme resolution.
This approach might technically works and should respects the rule that:
> *modifiers must not reference other modifiers*
I’d like to clarify:
* Is this pattern (themes defining brand slots, brands selecting them) the **intended way** to model such a system ?
* Are there other recommended approaches within the resolver model to express a true 2-dimensional choice like this ?
* Or is explicitly encoding the cross-product (one way or another) an expected limitation of the resolver?
I’m mainly looking to understand **intent and best practice**, rather than proposing a change to the spec.
### Prior art
_No response_
### Pros & cons
_No response_
### Alternatives
To help clarify how the resolver is intended to be used in practice, it would be extremely valuable to have one or more complete sample projects included with the specification or repository.
### Required
- [x] I have read and agree to abide by the [CODE_OF_CONDUCT](https://github.com/design-tokens/community-group/blob/CODE_OF_CONDUCT.md)
Please view or discuss this issue at https://github.com/design-tokens/community-group/issues/381 using your GitHub account
--
Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config
Received on Wednesday, 14 January 2026 07:46:43 UTC