My new ebook  Design Systems for Developers  is here! Start reading

Design

Consuming Design Tokens From Style Dictionary Across Platform-Specific Applications

Suggestions For An Automated Workflow

Last Updated: 2021-02-04

Table of Contents

1 | Introduction to Design Tokens
2 | Managing and Exporting Design Tokens With Style Dictionary
3 | Exporting Design Tokens From Figma With Style Dictionary
4 | Consuming Design Tokens From Style Dictionary Across Platform-Specific Applications
5 | Generating Design Token Theme Shades With Style Dictionary
6 | Documenting Design Tokens With Docusaurus
7 | Integrating Design Tokens With Tailwind
8 | Transferring High Fidelity From a Design File to Style Dictionary
9 | Scoring Design Tokens Adoption With OCLIF and PostCSS
10 | Bootstrap UI Components With Design Tokens And Headless UI
11 | Linting Design Tokens With Stylelint
12 | Stitching Styles to a Headless UI Using Design Tokens and Twind

What You’re Getting Into

In the previous article, I demonstrated how we can create an automated process to generate design tokens from a design file using a plugin and export them as platform deliverables using Style Dictionary and GitHub Actions.

I had mentioned a fictional scenario where we work for ZapShoes, an e-commerce application that ships shoes in a zap, and have been tasked with automating changes in the company’s design system to reflect across applications within the company that may be on different platforms with unique technologies.

By creating an automated process to create platform deliverables from the design file in a GitHub repository, we’ve solved most of my fictional problem.

Now that we have a central GitHub repository with our style dictionary that manages and exports design tokens, we’ll have to finish the problem by finding out the best way for different application to consume the platform deliverables, the exported design tokens for a specific technology.

Put it another way, we need to find a way to deliver design tokens across multiple applications within the fictional company. That way, there will be an automated process to reflect changes in a design file across an entire company.

This article will be less of a tutorial like the previous one and more of a discussion on best practices. Although, I’ll have some code samples for each practice to make the discussion more digestible.

Consuming Design Tokens From Style Dictionary With GraphQL

When I came across Shopify’s Polaris design system for the last article, I noticed that they expose a GraphQL API that serves their design tokens.

As a big fan of GraphQL, this was very intriguing, but it also sounded like a lot of unneeded overhead to generate an API to deliver design details.

However, it dawned on me that if you have a style dictionary in a central GitHub repository, we would not have to create our own GraphQL API.

Instead, we can use GitHub’s GraphQL API to read the platform deliverables in the output folder of that repository. In theory, those deliverables that are read could be stored using a technology’s file system API.

For example, a repository for a Vue application could contain a Node script that fetches its deliverables in the style dictionary using the GitHub GraphQL API and writes them to local files using the Node file system API.

Now, you may be used to calling APIs to load data while your application is running. However, what I am suggesting is calling your API when your application builds, before it runs.

An application builds as you develop locally as well as before new code is deployed to production.

So, where and when should something like the Node script I mentioned above be called?

If it is only called in the deployment process, before new code is deployed to a production site, then there would be no way to access the tokens while developing locally. This would result in the design tokens not being used which doesn’t make sense.

However, if the design tokens are fetched while developing locally and while deploying to production, then there is a risk that the tokens that are deployed do not match what the developer saw locally. This might be a rare timing issue but a risk nonetheless.

If the design tokens are fetched while developing locally, a script writes them to a folder, and that folder is committed to the origin of the repository, then there won’t be a risk of a discrepancy between local development and the production site.

A risk in this approach is ensuring that all applications in a company have working scripts that read and write the platform deliverables in the central style dictionary. Also, there would be a responsibility to reach each application to integrate this workflow into the development experience.

I can’t possibly iterate through all the possible examples within one platform-specific application, let alone all the various platform-specific applications and technologies that are out there.

However, let me use a React application as an example of how you might integrate the consumption of the design tokens into the development experience.

I have two solutions that came to mind.

Fetching Design Tokens Using Node and Husky

The first solution would be to leverage the prestart NPM script.

As the name implies, the prestart NPM script is triggered before running npm start.

NPM terms this a “life cycle” script, as it is a script that executes around the life cycle of a “default” script.

We could have prestart call a Node script that fetches the design tokens via the GitHub GraphAQL API and writes the tokens to a local folder (as suggested earlier).

Since the Node script would run before each npm start, we could integrate the workflow to retrieve the design tokens as part of the start-up process of our application.

This process of running npm start is already natural for local development as a JavaScript developer. However, there would be an additional strain on the developer to restart the application when switching between branches (working on a new feature).

This additional strain could be resolve using Husky, a library that lets you hook into Git event (push, pull, etc.) and run an NPM script.

Specifically, Husky could hook into when a developer changes from one branch to another in the repository. When that happens, the Node script to read and write the design tokens would be called again.

I put together a sample so you can visualize what I’m describing: https://github.com/michaelmang/consume-style-dictionary-node/commits/master

Sourcing Design Tokens With Gatsby

The second solution is to source from the GitHub GraphQL API in a Jamstack ecosystem, such as Gatsby.

You could have the Gatsby application source from the GitHub API which reads from the style dictionary repository. The design tokens then are available via Gatsby’s GraphQL data layer.

consuming design tokens from style dictionary across platform-specific applications

With the help of a plugin called gatsby-source-github-api, I can read the contents of a platform deliverable file from the style dictionary, like _variables.css

As you can see in the graphic above, the contents come back as plain text.

With some additional configuration with Gatsby, we’ll be able to transform this plain text into a better format.

Gatsby exposes a gatsby-node.js file to do things with their GraphQL data layer during the build lifecycle.

There are two ways in which “node” can be understood in Gatsby. First, the gatsby-node.js does allow us to write code to do things with their data layer using Node. Second, “node” refers to the “data tree.” A data tree is a way of visualizing the organization of data in computer science:

consuming design tokens from style dictionary across platform-specific applications

In Gatsby, the data layer (which you can explore and query using the GraphQL explorer that is launched when developing a Gatsby application locally) consists of “nodes.”

In the graphic of the GraphQL explorer that I posted above, there is a node representing each result from the GraphQL query of the GitHub API:

{
  allGithubData {
    nodes {
      rawResult {
        data {
          repository {
            content {
              entries {
                object {
                  text
                }
              }
            }
          }
        }
      }
    }
  }
}

In the query above, the text is the data within the node.

Gatsby exposes APIs that can be used in the gatsby-node.js file to transform the data in the GitHub node. Specifically, we could use the onCreateNode API to transform the text node, which is the platform deliverable represented as plain text, into multiple nodes representing the design tokens:

consuming design tokens from style dictionary across platform-specific applications

Here’s how I implemented it: https://github.com/michaelmang/consume-style-dictionary-gatsby/commits/master

With this approach, you wouldn’t need to copy the design tokens locally as the design tokens should be available when you build the application both locally and before the deployment. This doesn’t prevent the timing issue I mentioned earlier, but it is a pleasant pairing.

The design tokens could be queried from a component using Gatsby’s built-in tooling.

Thoughts On This Approach

First, bear in mind that GraphQL may not be the best means of communicating data across the range of platforms and technologies that the style dictionary supports. For that reason, you could use GitHub’s REST API. All the pros and cons of this approach would remain.

Second, if the transforming of the text into individual design token nodes is overkill (and it very well maybe), you could alternatively write the text to a CSS file. This would also be done in gatsby-node.js using the Node file system API.

Finally, while it was fun to create the code samples for these approaches (especially the Gatsby transformer plugin), I think better approaches come when you shift the paradigm from your applications “consuming” the deliverables in style dictionary to style dictionary “delivering” its deliverables.

Delivering Design Tokens

In the previous article, I created a GitHub Actions workflow in my style-dictionary repository:

You can view that workflow here: https://github.com/michaelmang/style-dictionary/blob/exporting-design-tokens-from-figma-with-style-dictionary/.github/workflows/export-tokens-on-input.yml

This workflow is triggered whenever a new design tokens file is received from Figma.

This workflow builds the JSON file representing the design tokens from Figma using Style Dictionary and commits the platform deliverables that were generated.

These generated platform deliverables were stored in an output folder.

We can chain a new workflow off of this previous workflow that is triggered whenever the output folder has been updated with new content.

When this happens, we’ll execute some actions that copy a file from the output folder and commits it to the repository of an application that is consuming the central style dictionary.

Since each application will only be interested in receiving a specific type of platform deliverable that was generated by Style Dictionary, we can create a separate “job” for each application.

Jobs in a GitHub Actions run in parallel by default.

So, on the push of new platform deliverables, each application that needs to consume one of these deliverables will have a job in the workflow to copy the needed deliverable to its repository.

This indeed means that for every new application that consumes the style dictionary, we would have to add a new job in the workflow.

However, we already have to update the Style Dictionary config every time we want it to generate a new platform deliverable. We’re just adding a step to the process.

consuming design tokens from style dictionary across platform-specific applications

consuming design tokens from style dictionary across platform-specific applications

Here’s an example of me copying the _variables.scss deliverable generated by Style Dictionary to a React application: https://github.com/michaelmang/style-dictionary/pull/3

And, the example application repository that the deliverable was copied to: https://github.com/michaelmang/consume-style-dictionary-github-actions

I leveraged a pre-defined action step for copying the deliverable to another repository.

Thoughts On This Approach

The only caveat was that it required a Linux virtual environment. However, it probably isn’t too difficult to write your own action step if that’s a problem.

Another caveat was that it uses HTTPS to clone and push to your repositories, so you’ll need to make sure the remote URL for the consuming is HTTPS and not SSH.

Overall, I think it is a much better option to think of delivering/shipping the platform deliverables to all the consuming applications, rather than having all the applications manage to consume the platform deliverables.

This approach also leaves a record of all the consuming applications as they each have their own job documented in the workflow.

Conclusion

Congratulations, you have all the skills necessary to automate the process of taking a design file and delivering the design tokens across as many applications, whatever the platform and whatever the technology. 🎉

Perhaps there are other ways to solve the automation problem. Or, maybe you have a better idea to inform a best practice, especially given that these problems have a much bigger scale than an article can cover.

A coworker once told me that the best part of coding was when you get to refactor. There’s some truth to that (as long as it isn’t a painful refactor of legacy code). I hope to not have given you all the solutions in this article, nor the best practices for every scenario, but some skills and inspiration to have fun refactoring the design tokens process.

In the next article, we'll learn how to generate design token theme shades with Style Dictionary.

Pow, share, and discuss.

Design Systems for Developers

Read my latest ebook on how to use design tokens to code production-ready design system assets.

Design Systems for Developers - Use Design Tokens To Launch Design Systems Into Production | Product Hunt

Michael Mangialardi is a software developer specializing in UI development with React and fluent in UI/UX design. As a survivor of impostor syndrome, he loves to make learning technical skills digestible and practical. Formerly, he published articles, ebooks, and coding challenges under his brand "Coding Artist." Today, he looks forward to using his mature experience to give back to the web development community. He lives in beautiful, historic Virginia with his wife.