Design Tokens Resolver Module

Preview

Draft Community Group Report

Latest published version:
https://www.designtokens.org/TR/drafts/resolver/
Editors:
Joren Broekema
Louis Chenais
Esther Cheran
Mike Kamminga
Andrew L’Homme
James Nash
Drew Powers
Matthew Ström-Awn
Lilith Wittmann
Feedback:
GitHub design-tokens/community-group (pull requests, new issue, open issues)

Abstract

This specification extends the format and describes a method to work with design tokens in multiple contexts (such as “light mode” and “dark mode” color themes).

Status of This Document

This is a preview

Do not attempt to implement this version of the specification. Do not reference this version as authoritative in any way.

This specification was published by the Design Tokens Community Group. It is not a W3C Standard nor is it on the W3C Standards Track. Please note that under the W3C Community Contributor License Agreement (CLA) there is a limited opt-out and other conditions apply. Learn more about W3C Community and Business Groups.

This is a snapshot of the editors’ draft. It is provided for discussion only and may change at any moment. Its publication here does not imply endorsement of its contents by W3C or the Design Tokens W3C Community Group Membership. Don’t cite this document other than as work in progress.

This document has been published to facilitate Wide Review.

This document was produced by the Design Tokens W3C Community Group, and contributions to this draft are governed by Community Contributor License Agreement (CLA), as specified by the W3C Community Group Process.

GitHub Issues are preferred for discussion of this specification.

1. Introduction

This section is non-normative.

Consumers of design tokens often need to express alternate values that apply in different contexts. Such examples include, but are not limited to:

However, these alternate contexts are susceptible to combinatorial explosion, making storage and management unwieldy.

This format describes a mechanism for deduplicating all repeat values of tokens across all contexts as well as enumerating all permutations of contexts.

2. Terminology

2.1 Orthogonal (orthogonality)

This section is non-normative.

A trait describing two or more contexts that each operate on exclusive tokens, i.e. do not overlap. Modifiers MAY be orthogonal, but it are not required to be.

Making modifiers orthogonal as much as possible reduces cognitive load and reduces user error.

2.2 Resolution

A resolution is a single possible permutation of a resolver document. A resolution maps 1:1 to an input, but the difference is the “input” refers to the modifier contexts used, whereas “resolution” refers to the final set of tokens and token values produced.

3. Filetype

3.1 Format

A resolver document MUST use standard JSON syntax ([RFC8259]).

Tools MAY support extensions such as JSONC or JSON5 so long as the document may be converted to normal JSON without affecting token values.

3.2 File extension

Users SHOULD use the .resolver.json file extension to name resolver documents.

3.3 MIME type

When transmitting a resolver document over HTTP, users SHOULD use the expected application/json MIME type ([RFC6838]) in the Content-Type header ([RFC1341]). Users SHOULD NOT use a custom or unexpected MIME type.

4. Syntax

4.1 Root level properties

A resolver document contains the following properties at the root level:

Name Type Required Description
name string A short, human-readable name for the document.
version YYYY-MM-DD Y Version. Must be 2025-10-01.
description string A human-readable description for this document.
sets Map[string, Set] Definition of sets.
modifiers Map[`string, Modifier] Definition of modifiers.
composition ReferenceObject[] Y Resolution of sets and modifiers.

4.1.1 Name

The document MAY provide a human-readable name at the root level. This is helpful to distinguish one resolver document from another, in case the filename itself isn’t enough.

4.1.2 Version

The document MUST provide a version at the root level, and it MUST be 2025-11-01. This is reserved for future versions in case breaking changes are introduced.

4.1.3 Description

The document MAY provide a description at the root level. This may be used to add additional explanation or context not present in name.

4.1.4 Sets

A set is a collection of design tokens in DTCG format. A set MUST contain a sources array with tokens declared directly, or a reference object pointing to a JSON file containing design tokens, or any combination of the two.

A set MAY include a description describing the purpose of the set.

If the array declares multiple sources, they will be merged in array order, meaning if a token is declared multiple times, the last occurrence in the array will be the final value. Tools MUST respect array ordering.

4.1.5 Modifiers

A modifier is similar to a set, but allows for conditional inclusion via the contexts map.

4.1.5.1 Contexts

A modifier MUST declare a contexts map of a string value to an array of token sources. The array of tokens sources MUST be a ReferenceObject, inline tokens, or any combination of the two.

A modifier SHOULD have two or more contexts, since one is the equivalent of a set. A modifier MUST NOT have an empty contexts map. Tools SHOULD throw an error for modifiers with only 1 context. Tools MUST throw an error for modifiers with 0 contexts.

Like sets, array order MUST be respected such that in case of conflict, the last occurrence of a token in the array produces the final value.

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.

4.1.5.2 Description

A modifier MAY declare a human-readable description.

4.1.5.3 Default

A modifier MAY declare a default value that MUST match one of the keys in contexts. Tools MUST throw an error if the value is not present in contexts.

4.1.5.4 Resolution count

The number of possible resolutions a document may generate may be predicted with the product of all contexts across all modifiers.

4.1.6 Composition

The composition key is an array of sets and modifiers ordered to produce the final result of tokens. The order is significant, with tokens later in the array overriding any tokens that came before them, in case of conflict.

4.1.6.1 Inline sets and modifiers

In composition, a set or modifier MAY be declared inline, so long as name and type keys are added to the object:

Property Type Required Description
name string Y A unique name that MUST NOT conflict with any other name in compositions.
type "set" | "modifier" Y MUST be "set" or "modifier" according to the type.

Tools MUST throw an error in the case where name or type are missing from an inline object, or if name is duplicated among any objects.

Editor's note: Name

Inline sets and modifiers MUST NOT be referenced in any way. Tools SHOULD throw an error when a reference object points to a composition item.

4.1.6.2 Ordering of sets and modifiers

This section is non-normative.

The composition array allows for any ordering of sets and modifiers to the user’s choosing. However, in the scenario that many sets must appear after the modifiers to resolve conflicts, it is likely a smell of unpredictable and brittle token organization. Ideally, modifiers handle conditional values so well they require few or no overrides (see orthogonality). In practical terms, this means that

4.2 Reference objects

When referring to another JSON document or a structure within the same document, a reference object MUST be used. This is described in JSON Schema 2020-12 as an object with a key of $ref whose string is a valid JSON pointer as described in [RFC6901].

Tools MUST resolve all reference objects in a resolver document.

Reference objects MUST NOT be circular, neither referencing other pointers that reference itself, nor referencing any parent node of the reference object.

4.2.1 Invalid pointers

A pointer MAY point anywhere within the same document, with the exception of the following:

  1. Only composition may reference a modifier (#/modifiers/…). Sets and modifiers MUST NOT reference another modifier.
    • Referencing a modifier from a set could cause inputs to apply conditional logic to a structure that can’t support it, therefore it’s not allowed.
    • Referencing a modifier from another modifier would mean a single input applies to unexpected modifiers, therefore it’s not allowed.
  2. A reference object MUST NOT point to anything in the composition array (#/composition/…). Composition, by its nature, references many other parts of the document. Duplicating any part of composition will produce complex, hard-to-predict chains.

Tools MUST throw an error if encountering any invalid pointers.

4.2.2 Extending

As JSON Schema 2020-12 allows, other keys MAY exist on a reference object alongside $ref. In these scenarios, the local keys alongside $ref MUST be treated as overrides.

If a key alongside $ref declares an object or array, tools MUST flatten these shallowly, meaning objects and arrays are not merged.

4.3 $extensions

An $extensions object MAY be added to any set, modifier, or inline set/modifier, to declare arbitrary metadata that is up to individual tools to either use or ignore.

If provided, $extensions MUST be an object with the keys being vendor-specific namespaces. This allows multiple tools to use this metadata without conflict.

4.4 $defs

Tools MAY allow defining structures in JSON Schema $defs but is not a requirement, and ultimately is up to the tool to decide.

Editor's note: $defs

5. Inputs

A resolver document only describes how conditional token values MAY be produced. But the conditions must still be provided somewhere. The term “input” refers to any selection of context values passed to the tool.

Tools MUST accept inputs as a JSON-serializable object, such as an object in JavaScript or a dictionary in Python.

Tools that load a resolver that declares modifiers SHOULD throw an error if an accompanying input is not provided.

5.1 Case sensitivity

Inputs SHOULD be case-insensitive. For example, { "theme": "dark" }, { "Theme": "Dark" }, and { "THEME": "DARK" } SHOULD be equivalent. However, tools MAY make individual decisions on case sensitivity.

5.2 Enforcing strings

Inputs MUST have strings as their values. Tools MUST throw an error if an input contains a non-string value, such as { "beta": true } or { "size": 100 }.

6. Resolution logic

Tools MUST handle the resolution stages in order to produce the correct output.

  1. Input validation: verifying the input is valid for the given resolver document.
  2. Composition: tracing the composition order to produce the final tokens structure.
  3. Aliases: resolving token aliases in the final tokens structure.
  4. Resolution: the final end result

6.1 Input validation

Tools MUST require all inputs match the provided modifier contexts.

If a resolver does NOT declare any modifiers, skip this step and proceed to Composition.

  1. For every key in the input object:
    1. Verify it corresponds with a valid modifier. If it does not, throw an error.
    2. Verify that key’s value corresponds with that modifier’s allowed values. If it does not, throw an error.
  2. For every modifier in the resolver:
    1. If that resolver does NOT declare a default value, verify a key is provided in the input. If not, throw an error.

6.2 Composition

Tools MUST iterate over the composition array in order.

  1. For every item in the array, determine whether it’s a set or modifier, flattening into a single tokens structure in array order.

    1. If the item is a set, combine the sources in array order to produce a single tokens structure.
    2. Otherwise, if the item is a modifier, select only the context that matches the input, combining the array in order to produce a single tokens structure.
    3. In case of a conflict, take the most recent occurrence in the array.
  2. Repeat until you’ve reached the end of the composition array.

The final result will be a tokens structure that behaves the same as if it were one source to begin with.

6.3 Aliases

Aliases MUST NOT be resolved until this step.

After the composition has been flattened into a single tokens structure, the only remaining step is resolving aliases. Aliases are resolved the exact same way as outlined in the format:

6.4 Resolution

7. Bundling

This section is non-normative.

A resolver document allows for the use of tokens to exist in multiple JSON files for organization. But for the purposes of portability, it may be advantageous to deal with only a single JSON document.

“Bundling” refers to the process by which a resolver document may be reduced down into a single file. There are multiple strategies to accomplish this, more than this document outlines. But for the purpose of illustration, this will outline 2 of the many possible approaches:

7.1 Inlining files

Inlining involves taking all reference objects to remote files, and replacing them with their contents. This is a simple strategy that accomplishes the end goal, but results in duplication whenever the same file is referenced multiple times. While a tool may not have any difficulty with duplicated tokens, a human reading this document may likely struggle reading the number of lines of code this would produce.

7.2 Using $defs for files

As described in $defs, $defs don’t have defined behavior in a resolver document. But they are valid pointers for reference objects. This strategy involves creating a top-level $defs key, with each top-level key containing the contents for that file.

There is no downside to using $defs other than the possibility of some tools not supporting it, since $defs is not a requirement of this spec.

8. Conformance

As well as sections marked as non-normative, all authoring guidelines, diagrams, examples, and notes in this specification are non-normative. Everything else in this specification is normative.

The key words MAY, MUST, MUST NOT, SHOULD, and SHOULD NOT in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.

Tools implementing the Resolver Specification MUST:

A. Acknowledgments

This section is non-normative.

This resolver spec wouldn’t have happened without the Hyma Team, including but not limited to Mike Kamminga, Andrew L’Homme, and Lilith. Significant contributions were also made by Joren Broekema, Louis Chenais. We thank the members of the Design Tokens Community Group for their contributions and feedback.

B. References

B.1 Normative references

[html]
HTML Standard. Anne van Kesteren; Domenic Denicola; Dominic Farolino; Ian Hickson; Philip Jägenstedt; Simon Pieters. WHATWG. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[RFC1341]
MIME (Multipurpose Internet Mail Extensions): Mechanisms for Specifying and Describing the Format of Internet Message Bodies. N. Borenstein; N. Freed. IETF. June 1992. Proposed Standard. URL: https://www.rfc-editor.org/rfc/rfc1341
[RFC2119]
Key words for use in RFCs to Indicate Requirement Levels. S. Bradner. IETF. March 1997. Best Current Practice. URL: https://www.rfc-editor.org/rfc/rfc2119
[RFC6838]
Media Type Specifications and Registration Procedures. N. Freed; J. Klensin; T. Hansen. IETF. January 2013. Best Current Practice. URL: https://www.rfc-editor.org/rfc/rfc6838
[RFC6901]
JavaScript Object Notation (JSON) Pointer. P. Bryan, Ed.; K. Zyp; M. Nottingham, Ed. IETF. April 2013. Proposed Standard. URL: https://www.rfc-editor.org/rfc/rfc6901
[RFC8174]
Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words. B. Leiba. IETF. May 2017. Best Current Practice. URL: https://www.rfc-editor.org/rfc/rfc8174
[RFC8259]
The JavaScript Object Notation (JSON) Data Interchange Format. T. Bray, Ed. IETF. December 2017. Internet Standard. URL: https://www.rfc-editor.org/rfc/rfc8259