Skip to content

Conversation

mikekamminga
Copy link
Contributor

This commit adds the Resolver specification working document which was originally created by the team at Hyma/Tokens Studio as a contribution to the DTCG working group and the evolution of Design Tokens standards and ecosystem.

All comments from the source Google doc — where earlier collaboration found place — which were open/unresolved have been included in this version as ISSUE blocks throughout the document and need to be discussed and resolved.

Changes

Introduction of resolver specification

How to Review

Early PR for early internal review

This commit adds the Resolver specification working document which was orginally created by the team at Hyma/Tokens Studio as a contribution to the DTCG working group and the evolution of  Design Tokens standards and ecosystem.

All comments from the source Google doc — where earlier collaration found place — which were open/unresolved have been included in this version as ISSUE blocks throughout the document and need to be discussed and resolved.
Copy link

netlify bot commented Jul 30, 2025

Deploy Preview for designtokensorg ready!

Name Link
🔨 Latest commit
🔍 Latest deploy log https://app.netlify.com/projects/designtokensorg/deploys/68c441c5087a56cffd27bc1c
😎 Deploy Preview https://deploy-preview-289--designtokensorg.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

* chore: format resolver module into markdown

* chore: run Prettier on CHANGELOG.md
<a href="./format/">Format</a>
</li>
<li><a href="./color/">Color</a></li>
<li>Animations (coming soon)</li>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔 I have no idea what happens to animations but in the future I’d love to resume this exploration (I’m no Val Head but I’m interested and have some knowledge here)

@drwpow
Copy link
Contributor

drwpow commented Aug 4, 2025

I have 2 PRs here that I’d like to break out into individual reviews, and go section-by-section:

1: #291
2. #292

In each PR I have made suggestions to improve the first 2–3 sections of this module, along with reasons behind each change. Would love thoughts/reviews on each individually to keep this PR less noisy 🙏

}
```

Resulting in tokens accessible via spacing.sm and spacing.lg.

This comment was marked as resolved.


**Namespace vs Alias Terminology:** Should the `alias` property be renamed to `namespace` to avoid confusion with token aliases (references to other tokens)?

**Redundancy with Modifier Names:** The `meta.alias` property may be redundant since modifiers already have a `name` property that could serve the same namespacing purpose.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i can see an author wanting to name a modifier but namespace it differently; 'name' might be useful in authoring contexts, whereas namespace might be used in a parsing/resolving context.


</td></tr><tr><th>

Input
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think my biggest hangup on the spec is the 'input' part. Currently, the way I understand it:

  1. All valid resolution paths are defined in a single resolver file
  2. To invoke a resolver, a tool needs input to select the desired resolution path

This introduces a step into the resolution process, whereby the tool needs to figure out if the resolution path is valid before continuing. It also means a user (or a tool working on the users's behalf) needs to understand the internal structure of the resolver file to use it correctly; a complex system might have dozens of resolution paths, and each needs an exact match on a string in the file to be called correctly.

I'd like to propose a different approach:

  1. A resolver file represents a single resolution path
    a. To indicate all the valid resolution paths, provide multiple resolver files
  2. To invoke a resolver, simply point a tool to the file that represents the desired resolution path

This means a user doesn't need to inspect or understand the inner workings of a resolver file to use it. They can call tool resolve 'brandADark.resolver.json' with no additional input to get the resolved token file.

If there's a concern about single-file vs. multi-file we might consider a resolver file that names/enumerates the resolvers as single resolution paths instead. But either way, the philosophy is 'one resolver, one resolution path'.

@drwpow drwpow mentioned this pull request Aug 28, 2025
@Sidnioulz
Copy link

Sidnioulz commented Oct 2, 2025

I wanna bring up another edge case / potential issue on order of resolution between sets.

Say I have the following resolver:

{
  "tokens": [
    // Sets my.only.token to #ff0000
    "base-set.json",
    {
      "type": "modifier",
      "name": "theme",
      "context": {
        // Sets my.only.token to #ffcccc
        "light": ["light.json"],
        // Sets my.only.token to #660000
        "dark": ["dark.json"]
      }
    },
    // Sets my.only.token to #0000ff
    "token-set-that-messes-everything-up.json"
  ]
}

What should the value of my.only.token be when there is no mode? When in light or dark mode?

I personally expect that resolutions should always be chained sequentially, because that gives me full power to decide on who has authority over the final value of a token. So I expect my.only.token to be #0000ff in every mode in this scenario.

Issue 3 on the spec makes it sound like mode precedence should be declared/decided regardless of the order in which modes are defined; whereas I believe the last-declared mode should take precedence, on a token-per-token basis.

So, if I have a resolver like:

{
  "tokens": [
    "org-wide/base.json",
    {
      "type": "modifier",
      "name": "color-scheme",
      "context": {
        "light": ["org-wide/light.json"],
        "dark": ["org-wide/dark.json"]
      }
    },
    {
      "type": "modifier",
      "name": "client-brand",
      "context": {
        "client-a": ["product-foo/clients/a.json"],
        "client-b": ["product-foo/clients/b.json"],
      }
    },
    {
      "type": "modifier",
      "name": "color-scheme",
      "context": {
        "light": ["product-foo/light.json"],
        "dark": ["product-foo/dark.json"]
      }
    },
  ]
}

There could be some tokens overridden by the client brand that then still get overridden by the more specific color-scheme mode sets. Maybe for instance a team enforces a specific outline color in dark mode to fix a contrast issue, which was previously customisable by clients but only worked in light color-schemes. But most tokens overridden in client brands ought to be preserved.

And so:

  • color.border.focus set in org-wide/dark.json, product-foo/clients/a.json, product-foo/dark.json and prioritises color-scheme modes
  • color.background.foo set in org-wide/dark.json and product-foo/clients/a.json and prioritises brand modes

If mode precedence was handled outside of the order in which sets are defined, and if it wasn't handled on a token-per-token basis, we'd then be unable to actually override any token after it's been tainted by a mode.

Or we'd have to say that tokens can only belong to a single mode to prevent these scenarios altogether (which reintroduces combinatioral explosion of modes when combining color blindness support, theming X white-label and color-scheme preferences).

The implication of what I'm requesting is dire, though: CSS outputs can preserve the prioritisation outlined in a chain of resolved sets. But Figma cannot yet. Tailwind and friends cannot yet. They'd need to find their own ways to handle specificity/priority in how a token value is set.

Comment on lines +227 to +230
"context": [
"light": ["light.json"],
"dark": ["dark.json"]
]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"context": [
"light": ["light.json"],
"dark": ["dark.json"]
]
"context": {
"light": ["light.json"],
"dark": ["dark.json"]
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants