Skip to content

Formats

Formats define the output of your created files. For example, to use your styles in CSS you use the css/variables format. This will create a CSS file containing the variables from your style dictionary.

Using formats

You use formats in your config file under platforms > [Platform] > files > [File] > format.

{
"source": ["tokens/**/*.json"],
"platforms": {
"css": {
"transformGroup": "css",
"files": [
{
"format": "css/variables",
"destination": "variables.css"
}
]
}
}
}

There is an extensive (but not exhaustive) list of built-in formats available in Style Dictionary.

Format configuration

Formats can take configuration to make them more flexible. This allows you to re-use the same format multiple times with different configurations or to allow the format to use data not defined in the tokens themselves. To configure a format, add extra attributes on the file options in your configuration like the following:

{
"source": ["tokens/**/*.json"],
"platforms": {
"scss": {
"transformGroup": "scss",
"files": [
{
"destination": "map.scss",
"format": "scss/map-deep",
"options": {
"mapName": "my-tokens"
}
}
]
}
}
}

In this example we are adding the mapName configuration to the scss/map-deep format. This will change the name of the SCSS map in the output. Not all formats have the configuration options; format configuration is defined by the format itself. To see the configuration options of a format, take a look at the documentation of the specific format.

Filtering tokens

A special file configuration is filter, which will filter the tokens before they get to the format. This allows you to re-use the same format to generate multiple files with different sets of tokens. Filtering tokens works by adding a filter attribute on the file object, where filter is:

  • An object which gets passed to Lodash’s filter method.
  • A string that references the name of a registered filter, using the registerFilter method
  • A function that takes a token and returns a boolean if the token should be included (true) or excluded (false). This is only available if you are defining your configuration in Javascript.
{
"destination": "destination",
"format": "myCustomFormat",
"filter": "myCustomFilter", // a named filter defined with .registerFilter
"filter": function(token) {}, // an inline function
"filter": {} // an object pass to lodash's filter method
}

The design token that is passed to the filter function has already been transformed and has default metadata added by Style Dictionary.

References in output files

Some formats can keep the references in the output. This is a bit hard to explain, so let’s look at an example. Say you have this very basic set of design tokens:

tokens.json
{
"color": {
"red": { "value": "#ff0000" },
"danger": { "value": "{color.red.value}" },
"error": { "value": "{color.danger.value}" }
}
}

With this configuration:

config.json
{
"source": ["tokens.json"],
"platforms": {
"css": {
"transformGroup": "css",
"files": [
{
"destination": "variables.css",
"format": "css/variables",
"options": {
// Look here 👇
"outputReferences": true
}
}
]
}
}
}

This would be the output:

variables.css
:root {
--color-red: #ff0000;
--color-danger: var(--color-red);
--color-error: var(--color-danger);
}

The css variables file now keeps the references you have in your Style Dictionary! This is useful for outputting themeable and dynamic code.

Without outputReferences: true Style Dictionary would resolve all references and the output would be:

variables.css
:root {
--color-red: #ff0000;
--color-danger: #ff0000;
--color-error: #ff0000;
}

It is also possible to provide a function instead of true or false to outputReferences, if you need to conditionally output references on a per token basis.

config.js
export default {
source: ['tokens.json'],
platforms: {
css: {
transformGroup: 'css',
files: [
{
destination: 'variables.css',
format: 'css/variables',
options: {
// Look here 👇
outputReferences: (token, { dictionary, usesDtcg }) => {
// `dictionary` contains `allTokens`, `tokens` and `unfilteredTokens` props
// `usesDtcg` tells you whether the Design Token Community Group spec is used with $ prefixes ($value, $type etc.)
// return true or false
},
},
},
],
},
},
};

Not all formats use the outputReferences option because that file format might not support it (like JSON for example). The current list of formats that handle outputReferences:

You can create custom formats that output references as well. See the Custom format with output references section.

Filtering out references

When combining filters with outputReferences, it could happen that a token is referencing another token that is getting filtered out. When that happens, Style Dictionary will throw a warning. However, it is possible to configure outputReferences to use our outputReferencesFilter utility function, which will prevent tokens that reference other tokens that are filtered out from outputting references, they will output the resolved values instead.

outputReferences with transitive transforms

When combining transitive value transforms with outputReferences, it could happen that a token that contains references has also been transitively transformed. What this means is that putting back the references in the output would mean we are undoing that work. In this scenario, it’s often preferable not to output a reference.

There is an outputReferencesTransformed utility function that takes care of checking if this happened and not outputting refs for tokens in this scenario.

File headers

By default Style Dictionary adds a file header comment in the top of files built using built-in formats like this:

variables.js
// Do not edit directly
// Generated on Sat, 01 Jan 2000 00:00:00 GMT

You can remove these comments with the option: showFileHeader: false if you do not want them in your generated files. You can also create your own file header or extend the default one. This could be useful if you want to put a version number or hash of the source files rather than a timestamp.

Custom file headers can be added the same way you would add a custom format, either by using the registerFileHeader function or adding the fileHeader object directly in the Style Dictionary configuration. Your custom file header can be used in built-in formats as well as custom formats. To use a custom file header in a custom format see the fileHeader format helper method.

build-tokens.js
import StyleDictionary from 'style-dictionary';
StyleDictionary.registerFileHeader({
name: 'myCustomHeader',
// This can be an async function as well
fileHeader: (defaultMessage) => {
// defaultMessage are the 2 lines above that appear in the default file header
// you can use this to add a message before or after the default message 👇
// the fileHeader function should return an array of strings
// which will be formatted in the proper comment style for a given format
return [...defaultMessage, `hello?`, `is it me you're looking for?`];
},
});

Then you can use your custom file header in a file similar to a custom format:

config.json
{
"source": ["tokens/**/*.json"],
"platforms": {
"css": {
"transformGroup": "css",
"files": [
{
"destination": "variables.css",
"format": "css/variables",
"options": {
"fileHeader": "myCustomHeader"
}
}
]
}
}
}

Which should output a file that will start like this:

variables.css
/**
* Do not edit directly
* Generated on Thu, 18 Mar 2021 21:30:47 GMT
* hello?
* is it me you're looking for?
*/

Custom formats

You can create custom formats using the registerFormat function or by directly including them in your configuration. A format has a name and a format function, which takes an object as the argument and should return a string which is then written to a file.

format

format.format(args)unknown

The format function that is called when Style Dictionary builds files.

ParamTypeDescription
argsObjectA single argument to support named parameters and destructuring.
args.dictionaryDictionaryTransformed Dictionary object containing allTokens, tokens and unfilteredTokens.
args.dictionary.allTokensTransformedToken[]Flattened array of all tokens, easiest to loop over and export to a flat format.
args.dictionary.tokensTransformedTokensAll tokens, still in unflattened object format.
args.dictionary.unfilteredAllTokensTransformedToken[]Flattened array of all tokens, including tokens that were filtered out by filters.
args.dictionary.unfilteredTokensTransformedTokensAll tokens, still in unflattened object format, including tokens that were filtered out by filters.
args.platformPlatformPlatform config
args.fileFileFile config
args.optionsObjectMerged object with SD Config & FormatOptions

Example:

StyleDictionary.registerFormat({
name: 'myCustomFormat',
format: function ({ dictionary, platform, options, file }) {
return JSON.stringify(dictionary.tokens, null, 2);
},
});

To use your custom format, you call it by name in the file configuration object:

{
"source": ["tokens/**/*.json"],
"platforms": {
"css": {
"options": {
"showFileHeader": true
},
"transformGroup": "css",
"files": [
{
"destination": "destination",
"format": "myCustomFormat",
"options": {
"showFileHeader": false
}
}
]
}
}
}

It is recommended for any configuration needed for your custom format to use the options object. Style Dictionary will merge platform and file options so that in your Style Dictionary configuration you can specify options at a platform or file level. In the configuration above, the options object passed to the format would have showFileHeader: false.

Custom return types

When writing outputs to the filesystem, the return type of the format function is always string. However, since v4 you can return any data format and use SD.formatAllPlatforms or SD.formatPlatform methods when you do not intend to write the output to the filesystem, but want to do something custom with the output instead.

Note that when you have a format that returns something that isn’t a string, you won’t be able to use it with buildPlatform or buildAllPlatforms methods, because they are writing to the filesystem and you can’t really write data to the filesystem that isn’t a string/buffer/stream.

This also means that the destination property is therefore optional for formats that aren’t ran by the build methods:

config.json
{
"source": ["tokens/**/*.json"],
"platforms": {
"css": {
"options": {
"showFileHeader": true
},
"transformGroup": "css",
"files": [
{
"format": "format-that-returns-array"
}
]
}
}
}
grabTokens.js
const sd = new StyleDictionary('config.json');
const cssTokens = (await sd.formatPlatform('css')).output;
/**
* Example:
* [
* ["--colors-red-500", "#ff0000"],
* ["--colors-blue-500", "#0000ff"]
* ]
*/

Custom format with output references

To take advantage of outputting references in your custom formats there are 2 helper methods in the dictionary argument passed to your format function: usesReference(value) and getReferences(value). Here is an example using those:

build-tokens.js
StyleDictionary.registerFormat({
name: `es6WithReferences`,
format: function ({ dictionary }) {
return dictionary.allTokens
.map((token) => {
let value = JSON.stringify(token.value);
// the `dictionary` object now has `usesReference()` and
// `getReferences()` methods. `usesReference()` will return true if
// the value has a reference in it. `getReferences()` will return
// an array of references to the whole tokens so that you can access their
// names or any other attributes.
if (dictionary.usesReference(token.original.value)) {
// Note: make sure to use `token.original.value` because
// `token.value` is already resolved at this point.
const refs = dictionary.getReferences(token.original.value);
refs.forEach((ref) => {
value = value.replace(ref.value, function () {
return `${ref.name}`;
});
});
}
return `export const ${token.name} = ${value};`;
})
.join(`\n`);
},
});

Using a template / templating engine to create a format

Formats are functions and created easily with most templating engines. Formats can be built using templates if there is a lot of boilerplate code to insert (e.g. ObjectiveC files). If the output consists of only the values (e.g. a flat SCSS variables file), writing a format function directly may be easier.

Any templating language can work as long as there is a node module for it. All you need to do is register a format that calls your template and returns a string.

Our recommendation is to use Template Literals for this as the easiest way to accomplish this:

build-tokens.js
import StyleDictionary from 'style-dictionary';
// Very simplistic/naive custom CSS format, just as an example, for CSS you should prefer using our predefined formats
const template = ({ dictionary, file, options, platform }) => `:root {
${dictionary.allTokens.map(token => ` ${token.name}`: `"${token.value}"`).join('\n')}
}
`;
StyleDictionary.registerFormat({
name: 'my/format',
format: template,
});
// format: 'my/format' is now available for use...

Here is a quick example for Lodash templates.

build-tokens.js
import StyleDictionary from 'style-dictionary';
import _ from 'lodash-es';
import fs from 'node:fs';
const template = _.template(fs.readFileSync('templates/myFormat.template'));
StyleDictionary.registerFormat({
name: 'my/format',
format: template,
});
// format: 'my/format' is now available for use...

And another example for Handlebars.

build-tokens.js
import StyleDictionary from 'style-dictionary';
import Handlebars from 'handlebars';
const template = Handlebars.compile(fs.readFileSync('templates/MyTemplate.hbs').toString());
StyleDictionary.registerFormat({
name: 'my/format',
format: function ({ dictionary, platform }) {
return template({
tokens: dictionary.tokens,
options: platform,
});
},
});
// format: 'my/format' is now available for use...