Always Twisted

A Design Tokens Workflow (part 3)

Beyond JSON: Exploring File Formats for Design Tokens

  1. Getting Started With Style Dictionary
  2. Outputting to Different Formats with Style Dictionary
  3. Beyond JSON: Exploring File Formats for Design Tokens – You are here
  4. Converting Tokens with Style Dictionary
  5. Organising Outputs with Style Dictionary
  6. Layers, referencing tokens in Style Dictionary
On This Page:

Before we go further into the series I thought we should take a look at the file formats you can use to generate your Design Tokens into the file outputs you need.

The code for this part of the series available to look at on Github.

While .json is the most common and natively supported format in Style Dictionary, it’s not the only option. When working with design tokens, choosing the right file format is crucial for readability, maintainability, and collaboration.

While .json is a great starting point for defining design tokens, it’s not always the most human-readable or flexible option, especially for larger or more complex token files. Custom parsers bridge this gap by enabling Style Dictionary to interpret other formats like .yaml, .hjson, .json5, and the Design Tokens Working Group formats .tokens and .tokens.json, giving you the freedom to choose what format best suits your team’s needs.

Let's Look At File Formats

.json

JSON is natively supported by Style Dictionary, making it the easiest format to start with. Its rigid structure ensures compatibility across platforms and tools, but the verbose syntax of braces, quotes, and commas could be challenging for large or deeply nested token sets.

Code languagejson
{
  "color": {
    "primary": {
      "$value": "#007bff"
    }
  }
}

.yaml

YAML is a human-readable, indentation-based syntax that reduces visual clutter, making it easier to manage for humans. It can especially useful for large, nested token sets and teams with non-developers, such as designers, working with token files.

color: primary:     $value: "#007bff"

.json5

JSON5 (JSON for humans) enhances JSON by allowing comments, trailing commas, and unquoted keys, making it a more forgiving and developer-friendly format. It’s a great option if you want JSON compatibility but also need to include notes or reduce syntax errors.

Code languagejson
{
  // Primary color
  color: {
    primary: { $value: "#007bff", }
  }
}

.hjson

HJSON simplifies JSON by removing the need for strict punctuation, making it more human-readable. It could be a good middle ground between YAML’s simplicity and JSON’s structure.

Code languagejson
{
  color: {
    primary: {
      $value: "#007bff"
    }
  }
}

.tokens and .tokens.json

The .tokens format follows the W3C Design Tokens Community Group specification, making it potentially future proof for new and existing tools and platforms. It retains the JSON structure but enforces standardised keys and metadata.

Code languagejson
{
  "$schema": "https://design-tokens.org/schema.json",
  "color": {
    "primary": {
      "$value": "#007bff"
    }
  }
}

Consuming Different File Formats

Let's look how Style Dictionary can consume these formats and what, if any, extra tools we need to install to compile your Design Tokens to your desired output files.

Natively Supported Formats

Style Dictionary natively supports .json and .tokens 'out of the box'. As previously shown in earlier articles to have your Design Tokens generate an output format (CSS Custom Properties for example) you need to define the source and platform details:

JSON

Code languagejavascript
module.exports = {
source: ['tokens/**/*.json'], // No extra setup needed
platforms: {
css: {
transformGroup: 'css',
buildPath: 'build/css/',
files: [
{
destination: 'color.css',
format: 'css/variables',
},
],
},
},
};

W3C .tokens

Code languagejavascript
module.exports = {
source: ['tokens/**/*.tokens'], // Works like JSON
platforms: {
css: {
transformGroup: 'css',
buildPath: 'build/css/',
files: [
{
destination: 'border.css',
format: 'css/variables',
},
],
},
},
};

Custom Parser Formats

To use a file format that is not supported natively you would need to install the relevant library and add a custom parser to the configuration file.

YAML

To install the YAML library

Code languagebash
npm install yaml

We would then create a custom parser for it

Code languagejavascript
import yaml from 'yaml';
StyleDictionary.registerParser({
name: 'yaml-parser',
pattern: /\.ya?ml$/,
parser: ({ contents }) => yaml.parse(contents),
});

We can then use .yaml as the source in the configuration

Code languagejavascript
module.exports = {
source: ['tokens/**/*.yaml'], // YAML files
parsers: ['yaml-parser'],
platforms: {
css: {
transformGroup: 'css',
buildPath: 'build/css/',
files: [
{
destination: 'typography.css',
format: 'css/variables',
},
],
},
},
};

JSON5

To install the JSON5 library.

Code languagebash
npm install json5

We can then create a custom parser for it.

Code languagejavascript
import json5 from 'json5';
StyleDictionary.registerParser({
name: 'json5-parser',
pattern: /\.json5$/,
parser: ({ contents }) => json5.parse(contents),
});

Again, we can then setup our configuration file to consume .json5 Design Token files

Code languagejavascript
module.exports = {
source: ['tokens/**/*.json5'],
parsers: ['json5-parser'],
platforms: {
css: {
transformGroup: 'css',
buildPath: 'build/css/',
files: [
{
destination: 'spacing.css',
format: 'css/variables',
},
],
},
},
};

HJSON

To install the HJSON library.

Code languagebash
npm install hjson

Again, we need to create a custom parser

Code languagejavascript
import hjson from 'hjson';
StyleDictionary.registerParser({
name: 'hjson-parser',
pattern: /\.hjson$/,
parser: ({ contents }) => hjson.parse(contents),
});

Then, we can set up the configuration file to use .hjson files

Code languagejavascript
module.exports = {
source: ['tokens/**/*.hjson'],
parsers: ['hjson-parser'],
platforms: {
css: {
transformGroup: 'css',
buildPath: 'build/css/',
files: [
{
destination: 'animation.css',
format: 'css/variables',
},
],
},
},
};

Bringing it all together

Not that I think you would or should decide to use multiple file formats to be consumed by Style Dictionary I think, for this article and example I'll tie all the options into a single config file.

If we have installed all the packages above we can then include them in our config file along with the custom parsers and also include these file formats as our possible sources:

Code languagejavascript
import StyleDictionary from 'style-dictionary';
import yaml from 'yaml';
import json5 from 'json5';
import hjson from 'hjson';
// Register custom parsers for YAML, JSON5, and HJSON
StyleDictionary.registerParser({
name: 'yaml-parser',
pattern: /\.ya?ml$/,
parser: ({ contents }) => yaml.parse(contents),
});
StyleDictionary.registerParser({
name: 'json5-parser',
pattern: /\.json5$/,
parser: ({ contents }) => json5.parse(contents),
});
StyleDictionary.registerParser({
name: 'hjson-parser',
pattern: /\.hjson$/,
parser: ({ contents }) => hjson.parse(contents),
});
// Configure Style Dictionary
const myStyleDictionary = new StyleDictionary({
source: [
`src/tokens/**/*.json`, // JSON (native)
`src/tokens/**/*.tokens`,// TOKENS (native)
`src/tokens/**/*.yaml`, // YAML (custom parser)
`src/tokens/**/*.json5`, // JSON5 (custom parser)
`src/tokens/**/*.hjson`, // HJSON (custom parser)
],
parsers: ['yaml-parser', 'json5-parser', 'hjson-parser'], // Custom parsers
platforms: {
css: {
transformGroup: 'css',
buildPath: 'build/',
files: [
{
destination: 'all.css',
format: 'css/variables',
},
],
},
},
});
// Build all platforms
await myStyleDictionary.buildAllPlatforms();

Let's create a simple set of Design Tokens for each file format:

color.json

Code languagejson
{
"color": {
"primary": { "$value": "#007bff" },
"secondary": { "$value": "#6c757d" }
}
}

border.tokens

{ "$schema": "https://design-tokens.org/schema.json", "border": { "radius": { "small": { "$value": "4px" }, "large": { "$value": "8px" } } } }

typography.yaml

typography: font: family: body: { $value: "Roboto, sans-serif" } heading: { $value: "Arial, sans-serif" } size: small: { $value: "0.875rem" } large: { $value: "1.25rem" }

spacing.json5

Code languagejson
{
spacing: {
none: { $value: "0" },
small: { $value: "0.5rem" },
medium: { $value: "1rem" },
large: { $value: "2rem" }
}
}

animation.hjson

{ animation: { duration: { short: { $value: "200ms" }, medium: { $value: "500ms" }, long: { $value: "1000ms" } } } }

When running the build.js file we will get a new CSS file containing all of these tokens as CSS custom properties:

Code languagecss
/**
* Do not edit directly, this file was auto-generated.
*/
:root {
--color-primary: #007bff;
--color-secondary: #6c757d;
--border-radius-small: 4px;
--border-radius-large: 8px;
--typography-font-family-body: Roboto, sans-serif;
--typography-font-family-heading: Arial, sans-serif;
--typography-font-size-small: 0.875rem;
--typography-font-size-large: 1.25rem;
--spacing-none: 0;
--spacing-small: 0.5rem;
--spacing-medium: 1rem;
--spacing-large: 2rem;
--animation-duration-short: 200ms;
--animation-duration-medium: 500ms;
--animation-duration-long: 1000ms;
}

With the configuration and example tokens above, we’ve successfully demonstrated how to use different file formats to define design tokens and process them into a single output format.

This setup showcases the flexibility of Style Dictionary, enabling teams to choose the format that best suits their workflows while maintaining consistency in the output.

In the next part of this series, we’ll return to using .json as our design token format and dive into one of Style Dictionary’s most powerful features: automatic value transformations.

Style Dictionary allows you to define tokens in a single format, such as pixels (px), and then automatically convert them to other units based on your project’s needs. For example, you can set up tokens in px for mobile apps and have them automatically converted to rem for web development, ensuring consistent and accessible scaling.

We’ll also explore how these transformations can handle other use cases, like generating fallback colours for older browsers or converting colour formats from HEX to RGB. This flexibility reduces manual work and ensures your tokens are ready for use across multiple platforms. Stay tuned to see how these transformations can simplify and enhance your design token workflow!

Wondering how to output tokens into different formats for different platforms?

I can configure tools to output tokens into the formats your teams need.

get in touch!