This document describes the technical specification for a file format to exchange design tokens between different tools.
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 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 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.
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.
This section is non normative
Design tokens are a methodology for expressing design decisions in a platform-agnostic way so that they can be shared across different disciplines, tools, and technologies. They help establish a common vocabulary across organisations.
There is a growing ecosystem of tools for design system maintainers and consumers that incorporate design token functionality, or would benefit from doing so:
It is often desirable for design system teams to integrate such tools together, so that design token data can flow between design and development tools.
For example:
While many tools now offer APIs to access design tokens or the ability to export design tokens as a file, these are all tool-specific. The burden is therefore on design system teams to create and maintain their own, bespoke "glue" code or workflows. Furthermore, if teams want to migrate to different tools, they will need to update those integrations.
This specification aims to facilitate better interoperability between tools and thus lower the work design system teams need to do to integrate them by defining a standard file format for expressing design token data.
These definitions are focused on the technical aspects of the specification, aimed at implementers such as design tool vendors. Definitions for designers and developers are available at designtokens.org.
A (Design) Token is an information associated with a name, at minimum a name/value pair.
For example:
color-text-primary: #000000;
font-size-heading-level-1: 44px;
The name may be associated with additional Token Properties.
Information associated with a token name.
For example:
A design tool is a tool for visual design creation and editing.
For example:
Design token translation tools translate token data from one format to another.
For example:
A documentation tool is a tool for documenting design tokens usage.
For example:
A token's type is a predefined categorization applied to the token's value.
For example:
Token tools can use Types to infer the purpose of a token.
For example:
A group is a set of tokens belonging to a specific category.
For example:
Groups are arbitrary and tools SHOULD NOT use them to infer the type or purpose of design tokens.
A design token's value can be a reference to another token. The same value can have multiple names or aliases.
The following Sass example illustrates this concept:
$color-palette-black: #000000;
$color-text-primary: $color-palette-black;
The value of $color-text-primary
is #000000
, because $color-text-primary
references $color-palette-black
. We can also say $color-text-primary
is an alias for $color-palette-black.
A design token whose value is made up of multiple, named child values. Composite tokens are useful for closely related style properties that are always applied together. For example, a typography style might be made up of a font name, font size, line height, and color.
Here's an example of a composite shadow token:
{
"shadow-token": {
"$type": "shadow",
"$value": {
"color": "#00000088",
"offsetX": "0.5rem",
"offsetY": "0.5rem",
"blur": "1.5rem",
"spread": "0rem"
}
}
}
Design token files are JSON (https://www.json.org/) files that adhere to the structure described in this specification.
JSON was chosen as an interchange format on the basis of:
When serving design token files via HTTP / HTTPS or in any other scenario where a media type (formerly known as MIME type) needs to be specified, the following MIME type SHOULD be used for design token files:
application/design-tokens+json
However, since every design token file is a valid JSON file, they MAY be served using the JSON media type: application/json
. The above, more specific media type is preferred and SHOULD be used wherever possible.
Tools that can open design token files MUST support both media types.
When saving design token files on a local file system, it can be useful to have a distinct file extension as this makes them easier to spot in file browsers. It may also help to associate a file icon and a preferred application for opening those files. The following file extensions are recommended by this spec:
.tokens
.tokens.json
The former is more succinct. However, until this format is widely adopted and supported, the latter might be useful to make design token files open in users' preferred JSON editors.
Tools that can open design token files MAY filter available files (e.g. in an open file dialog) to only show ones using those extensions. It is recommended to also provide users with a way of opening files that do not use those extensions (e.g. a "show all files" option or similar).
Tools that can save design token files SHOULD append one of the recommended file extensions to the filename when saving.
The group is currently exploring the addition of a JSON Schema to support the spec.
A concern about file size limitations of JSON files was raised by one of the vendors. The working group continues to gather feedback about any limitations the JSON format imposes.
An object with a $value
property is a token. Thus, $value
is a reserved word in our spec, meaning you can't have a token whose name is "$value". The parent object's key is the token name.
The example above therefore defines 1 design token with the following properties:
Name and value are both required.
Token names are case-sensitive, so the following example with 2 tokens in the same group whose names only differ in case is valid:
However, some tools MAY need to transform names when exporting to other languages or displaying names to the user, so having token names that differ only in case is likely to cause identical and undesirable duplicates in the output. For example, a translation tool that converts these tokens to Sass code would generate problematic output like this:
Tools MAY display a warning when token names differ only by case.
All properties defined by this format are prefixed with the dollar sign ($
). This convention will also be used for any new properties introduced by future versions of this spec. Therefore, token and group names MUST NOT begin with the $
character.
Furthermore, due to the syntax used for token aliases the following characters MUST NOT be used anywhere in a token or group name:
{
(left curly bracket)}
(right curly bracket).
(period)
Because of the decision to prefix group properties with a dollar sign ($
), token properties will also use a dollar sign prefix. This provides a consistent syntax across the spec.
While $value
is the only required property for a token, a number of additional properties MAY be added:
A plain text description explaining the token's purpose can be provided via the optional $description
property. Tools MAY use the description in various ways.
For example:
The value of the $description
property MUST be a plain JSON string, for example:
Design tokens always have an unambiguous type, so that tools can reliably interpret their value.
A token's type can be specified by the optional $type
property. If the $type
property is not set on a token, then the token's type MUST be determined as follows:
$type
property, then the token's type is inherited from the closest parent group with a $type
property.string
, number
, boolean
, object
, array
or null
) its value is.Tools MUST NOT attempt to guess the type of a token by inspecting the contents of its value.
The $type
property can be set on different levels:
The $type
property MUST be a plain JSON string, whose value is string
, number
, boolean
, object
, array
, null
or one of the values specified in respective type chapters. The value of $type
is case-sensitive.
For example:
The optional $extensions
property is an object where tools MAY add proprietary, user-, team- or vendor-specific data to a design token. When doing so, each tool MUST use a vendor-specific key whose value MAY be any valid JSON data.
In order to maintain interoperability between tools that support this format, teams and tools SHOULD restrict their usage of extension data to optional meta-data that is not crucial to understanding that token's value.
Tool vendors are encouraged to publicly share specifications of their extension data wherever possible. That way other tools can add support for them without needing to reverse engineer the extension data. Popular extensions could also be incorporated as standardized features in future revisions of this specification.
The extensions section is not limited to vendors. All token users can add additional data in this section for their own purposes.
A file MAY contain many tokens and they MAY be nested arbitrarily in groups like so:
The names of the groups leading to a given token (including that token's name) are that token's path, which is a computed property. It is not specified in the file, but parsers that conform to this spec MUST be able to expose the path of a token. The above example, therefore, defines 4 design tokens with the following properties:
Because groupings are arbitrary, tools MUST NOT use them to infer the type or purpose of design tokens.
Groups items (i.e. the tokens and/or nested groups) are unordered. In other words, there is no implicit order between items within a group. Therefore, tools that parse or write design token files are not required to preserve the source order of items in a group.
The names of items in a group are case sensitive. As per the guidance in the design token chapter, tools MAY display a warning to users when groups contain items whose names differ only in case and could therefore lead to naming clashes when exported.
The format editors acknowledge existing best-practices for token naming, but place no direct constraints on naming via the specification.
To prevent collisions with token names, token properties are prefixed with a dollar sign ($
). Using this prefix eliminates the need for a reserved words list and helps future-proof the spec.
Group keys without a dollar sign ($
) prefix denote:
A token name: distinguishable by containing a $value
property
{
"Group of tokens": {
"$description": "This is an example of a group containing a single token",
"Token name": {
"$value": "#000000"
}
}
}
A nested group name: distinguishable by not having a $value
property
{
"Group of tokens": {
"$description": "This is an example of a group containing a nested group",
"Subgroup of tokens": {
"Token 1 name": {
"$value": "#aabbcc"
},
"Token 2 name": {
"$value": "#ddeeff"
}
}
}
}
Groups MAY include an optional $description
property, whose value MUST be a plain JSON string. Its purpose is to describe the group itself.
For example:
Suggested ways tools MAY use this property are:
Groups may support additional properties like type and description. Should other properties be supported at the group level?
Groups MAY include an optional $type
property so a type property does not need to be manually added to every token. See supported "Types" for more information.
If a group has a $type
property it acts as a default type for any tokens within the group, including ones in nested groups, that do not explicity declare a type via their own $type
property. For the full set of rules by which a design token's type is determined, please refer to the design token type property chapter.
For example:
Tools that let users pick or edit tokens via a GUI MAY use the grouping structure to display a suitable form of progressive disclosure, such as a collapsible tree view.
Token names are not guaranteed to be unique within the same file. The same name can be used in different groups. Also, translation tools MAY need to export design tokens in a uniquely identifiable way, such as variables in code. Translation tools SHOULD therefore use design tokens' paths as these are unique within a file.
For example, a translation tool like Style Dictionary might use the following design token file:
...and output it as Sass variables like so by concatenating the path to create variable names:
Instead of having explicit values, tokens can reference the value of another token. To put it another way, a token can be an alias for another token. This spec considers the terms "alias" and "reference" to be synonyms and uses them interchangeably.
Aliases are useful for:
For a design token to reference another, its value MUST be a string containing the period-separated (.
) path to the token it's referencing enclosed in curly brackets.
For example:
When a tool needs the actual value of a token it MUST resolve the reference - i.e. lookup the token being referenced and fetch its value. In the above example, the "alias name" token's value would resolve to 1234 because it references the token whose path is {group name.token name}
which has the value 1234.
Tools SHOULD preserve references and therefore only resolve them whenever the actual value needs to be retrieved. For instance, in a design tool, changes to the value of a token being referenced by aliases SHOULD be reflected wherever those aliases are being used.
Aliases MAY reference other aliases. In this case, tools MUST follow each reference until they find a token with an explicit value. Circular references are not allowed. If a design token file contains circular references, then the value of all tokens in that chain is unknown and an appropriate error or warning message SHOULD be displayed to the user.
The format editors are currently researching JSON Pointer syntax to inform the exact syntax for aliases in tokens. https://datatracker.ietf.org/doc/html/rfc6901#section-5
Many tools need to know what kind of value a given token represents to process it sensibly. Translation tools MAY need to convert or format tokens differently depending on their type. Design tools MAY present the user with different kinds of input when editing tokens of a certain type (such as color picker, slider, text input, etc.). Style guide generators MAY use different kinds of previews for different types of tokens.
Since design token files are JSON files, all the basic JSON types are available:
Additionally, this spec defines a number of more design-focused types. To set a token to one of these types, it MUST either have a $type
property specifying the chosen type, inherit a type from one of its parent groups, or be an alias of a token that has the desired type. Furthermore, that token's value MUST then follow rules and syntax for the chosen type as defined by this spec.
If no explicit type has been set for a token, tools MUST treat values as one of the basic JSON types and not attempt to infer any other type from the value.
If an explicit type is set, but the value does not match the expected syntax then that token is invalid and an appropriate error SHOULD be displayed to the user. To put it another way, the $type
property is a declaration of what kind of values are permissible for the token. (This is similar to typing in programming languages like Java or TypeScript, where a value not compatible with the declared type causes a compilation error).
Represents a 24bit RGB or 24+8bit RGBA color in the sRGB color space. The $type
property MUST be set to the string color
. The value MUST be a string containing a hex triplet/quartet including the preceding #
character. To support other color spaces, such as HSL, translation tools SHOULD convert color tokens to the equivalent value as needed.
For example, initially the color tokens MAY be defined as such:
Then, the output from a tool's conversion to HSL(A) MAY look something like:
Represents an amount of distance in a single dimension in the UI, such as a position, width, height, radius, or thickness. The $type
property MUST be set to the string dimension
. The value must be a string containing a number (either integer or floating-point) followed by either a "px" or "rem" unit (future spec iterations may add support for additional units).
For example:
The "px" and "rem" units are to be interpreted the same way they are in CSS:
A naive approach like the one below may be appropriate for the first stage of the specification, but this could be more complicated than it seems due to platform/OS/browser restrictions.
Represents a font name or an array of font names (ordered from most to least preferred). The $type
property MUST be set to the string fontFamily
. The value MUST either be a string value containing a single font name or an array of strings, each being a single font name.
For example:
Represents a font weight. The $type
property MUST be set to the string fontWeight
. The value must either be a number value in the range [1, 1000] or one of the pre-defined string values defined in the table below.
Lower numbers represent lighter weights, and higher numbers represent thicker weights, as per the OpenType wght
tag specification. The pre-defined string values are aliases for specific numeric values. For example 100
, "thin"
and "hairline"
are all the exact same value.
numeric value | string value aliases |
---|---|
100 |
thin , hairline |
200 |
extra-light , ultra-light |
300 |
light |
400 |
normal , regular , book |
500 |
medium |
600 |
semi-bold , demi-bold |
700 |
bold |
800 |
extra-bold , ultra-bold |
900 |
black , heavy |
950 |
extra-black , ultra-black |
Number values outside of the [1, 1000] range and any other string values, including ones that differ only in case, are invalid and MUST be rejected by tools.
Example:
Represents the length of time in milliseconds an animation or animation cycle takes to complete, such as 200 milliseconds. The $type
property MUST be set to the string duration
. The value MUST be a string containing a number (either integer or floating-point) followed by an "ms" unit. A millisecond is a unit of time equal to one thousandth of a second.
For example:
Represents how the value of an animated property progresses towards completion over the duration of an animation, effectively creating visual effects such as acceleration, deceleration, and bounce. The $type
property MUST be set to the string cubicBezier
. The value MUST be an array containing four numbers. These numbers represent two points (P1, P2) with one x coordinate and one y coordinate each [P1x, P1y, P2x, P2y]. The y coordinates of P1 and P2 can be any real number in the range [-∞, ∞], but the x coordinates are restricted to the range [0, 1].
For example:
This section is non-normative.
Types still to be documented here are likely to include:
The types defined in the previous chapters such as color and dimension all have singular values. For example, the value of a color token is one color. However, there are other aspects of UI designs that are a combination of multiple values. For instance, a shadow style is a combination of a color, X & Y offsets, a blur radius and a spread radius.
Every shadow style has the exact same parts (color, X & Y offsets, etc.), but their respective values will differ. Furthermore, each part's value (which is also known as a "sub-value") is always of the same type. A shadow's color must always be a color value, its X offset must always be a dimension value, and so on. Shadow styles are therefore combinations of values that follow a pre-defined structure. In other words, shadow styles are themselves a type. Types like this are called composite types.
Specifically, a composite type has the following characteristics:
"#ff0000"
) or references to other design tokens that have sub-value's type (e.g. "{some.other.token}"
).A design token whose type happens to be a composite type is sometimes also called a composite (design) token. Besides their type, there is nothing special about composite tokens. They can have all the other additional properties like $description
or $extensions
. They can also be referenced by other design tokens.
At first glance, groups and composite tokens might look very similar. However, they are intended to solve different problems and therefore have some important differences:
Represents the style applied to lines or borders. The $type
property MUST be set to the string strokeStyle
. The value MUST be either:
stroke-linejoin
, stroke-miterlimit
and stroke-dashoffset
attributes)?
String stroke style values MUST be set to one of the following, pre-defined values:
solid
dashed
dotted
double
groove
ridge
outset
inset
These values have the same meaning as the equivalent "line style" values in CSS. As per the CSS spec, their exact rendering is therefore implementation specific. For example, the length of dashes and gaps in the dashed
style may vary between different tools.
Object stroke style values MUST have the following properties:
dashArray
: An array of dimension values and/or references to dimension tokens, which specify the lengths of alternating dashes and gaps. If an odd number of values is provided, then the list of values is repeated to yield an even number of values.lineCap
: One of the following pre-defined string values: "round"
, "butt"
or "square"
. These values have the same meaning as those of the stroke-linecap
attribute in SVG.The string and object values are mutually exclusive means of expressing stroke styles. For example, some of the string values like inset
or groove
cannot be expressed in terms of a dashArray
and lineCap
as they require some implementation-specific means of lightening or darkening the color for portions of a border or outline. Conversely, a precisely defined combination of dashArray
and lineCap
sub-values is not guaranteed to produce the same visual result as the dashed
or dotted
keywords as they are implementation-specific.
Furthermore, some tools and platforms may not support the full range of stroke styles that design tokens of this type can represent. When displaying or exporting a strokeStyle
token whose value they don't natively support, they should therefore fallback to the closest approximation that they do support.
The specifics of how a "closest approximation" is chosen are implementation-specific. However, the following examples illustrate what fallbacks tools MAY use in some scenarios.
Represents a border style. The $type
property MUST be set to the string border
. The value MUST be an object with the following properties:
color
: The color of the border. The value of this property MUST be a valid color value or a reference to a color token.width
: The width or thickness of the border. The value of this property MUST be a valid dimension value or a reference to a dimension token.style
: The border's style. The value of this property MUST be a valid stroke style value or a reference to a stroke style token.Represents a animated transition between two states. The $type
property MUST be set to the string transition
. The value MUST be an object with the following properties:
duration
: The duration of the transition. The value of this property MUST be a valid duration value or a reference to a duration token.delay
: The time to wait before the transition begins. The value of this property MUST be a valid duration value or a reference to a duration token.timingFunction
: The color of the shadow. The value of this property MUST be a valid cubic bézier value or a reference to a cubic bézier token.Represents a shadow style. The $type
property MUST be set to the string shadow
. The value must be an object with the following properties:
color
: The color of the shadow. The value of this property MUST be a valid color value or a reference to a color token.offsetX
: The horizontal offset that shadow has from the element it is applied to. The value of this property MUST be a valid dimension value or a reference to a dimension token.offsetY
: The vertical offset that shadow has from the element it is applied to. The value of this property MUST be a valid dimension value or a reference to a dimension token.blur
: The blur radius that is applied to the shadow. The value of this property MUST be a valid dimension value or a reference to a dimension token.spread
: The amount by which to expand or contract the shadow. The value of this property MUST be a valid dimension value or a reference to a dimension token.Represents a color gradient. The $type
property MUST be set to the string gradient
. The value MUST be an array of objects representing gradient stops that have the following structure:
color
: The color value at the stop's position on the gradient. The value of this property MUST be a valid color value or a reference to a color token.position
: The position of the stop along the gradient's axis. The value of this property MUST be a valid number value or reference to a number token. The number values must be in the range [0, 1], where 0 represents the start position of the gradient's axis and 1 the end position. If a number value outside of that range is given, it MUST be considered as if it were clamped to the range [0, 1]. For example, a value of 42 should be treated as if it were 1, i.e. the end position of the gradient axis. Similarly, a value of -99 should be treated as if it were 0, i.e. the start position of the gradient axis.If there are no stops at the very beginning or end of the gradient axis (i.e. with position
0 or 1, respectively), then the color from the stop closest to each end should be extended to that end of the axis.
Represents a typographic style. The $type
property MUST be set to the string typography
. The value MUST be an object with the following properties:
fontFamily
: The typography's font. The value of this property MUST be a valid font family value or a reference to a font family token.fontSize
: The size of the typography. The value of this property MUST be a valid dimension value or a reference to a dimension token.fontWeight
: The weight of the typography. The value of this property MUST be a valid font weight or a reference to a font weight token.letterSpacing
: The horizontal spacing between characters. The value of this property MUST be a valid dimension value or a reference to a dimension token.lineHeight
: The vertical spacing between lines of typography. The value of this property MUST be a valid JSON string or a reference to a string token.Is the current specification for typography styles fit for purpose? Should the lineHeight
sub-value use a number value, dimension or a new lineHeight type?
Referenced in: