Design tokens

Introduction to Design Tokens

Cynthia Mo

Engineer I

  • June 17, 2022
  • 12 min read

The DLS is American Express’ Design Language System, and we provide a collection of style guidelines, reusable components, and the code that supports them. We are always striving to innovate, so we are proud to announce design tokens in our next major version, DLS v7. We are still working out naming conventions and the final structure, but we are excited to introduce design tokens and show how you can use them!

As a side note, you will see the “Colossus” name appear a few times in this post. “Colossus” is what we use to refer to the DLS v7 major version in order to create a clear distinction.

Overview of Design Tokens

Design tokens are centralized, atomic pieces of UI information that make up a design system. They are essentially just design decisions, such as colors and typography, that provide a consistent and cohesive brand experience across our products. Incorporating them into our design system will improve the collaboration among product, design, and developers. If you are curious about atomic design, Brad Frost’s blog post is a great place to start.

Here is an example of how design tokens can be used to style the primary button component. As you can see, the design decisions include the background color (button-bg-primary), the vertical padding (button-padding-vertical), the horizontal padding (button-padding-horizontal), and the text color (button-text-primary). Those four values are design tokens, and they dictate how the button looks and feels.

One DLS Primary Button Design Tokens

The screenshot above shows a primary button and its design tokens.

If you are interested in looking at a more mature design token system, Salesforce’s Lightning Design System is a great example of design tokens in production.

The Value of Design Tokens

Design tokens bring many benefits to a design system, and we would like to highlight the most exciting ones.

Reduced Maintenance Effort

Currently, a lot of values are hardcoded across our products. For example, we ran a search across all repositories for our well known bright-blue color (HEX code #006FCF) and found over 9000 results. We found similar results for other values such as spacing. Over time, this becomes a maintenance nightmare. If the DLS updates any of its values, every hardcoded instance would need to be manually changed. This creates an opportunity for the DLS and our products to become misaligned, which can introduce inconsistencies to our brand experience.

With design tokens, the style values will exist in our design dictionary, which is our single source of truth (more on this later). Any updates to the DLS values will take place in this repository and cascade down to our consumers.

Custom Components

Sometimes teams need custom components that are not offered in the DLS, but they might still want to leverage DLS design decisions, such as colors and spacing values. Right now, our users can use the utility class names for some of the styles. For example, adding padding-2 to a React component’s className attribute will bring in the DLS’ values for padding-2, which adds 20px of padding to the top, bottom, left, and right. However, this does not cover all use cases. Let us explore one common scenario.

Example Scenario

.your-custom-element {

/* DLS bright blue */

border: 1px solid #006fcf;

}

The above screenshot shows a CSS rule with hardcoded color HEX values.

You are writing CSS or SASS and you want to apply the bright blue color to an element, which is perfectly valid. Here we are trying to apply a DLS bright blue color to the border. We do not have a class name for border color. Furthermore, we do not have CSS variables, so you will have to hardcode the color and leave a comment for your team. This is how hardcoded values get introduced, which brings us to the maintenance efforts mentioned above.

This does not just apply to borders. It is infeasible for the DLS to provide a class name for every property that a color or a spacing value can appear in.

Theming

Our design tokens allow teams to use the DLS while keeping their own custom brand styles. For example, if we wanted a Gold or Platinum custom section but wanted to use the default styling for the rest of the page, then design tokens would make that possible.

Dark Mode Support

Design tokens enable us to support dark tokens more easily. Going back to the hardcoded values point above, if we ever wanted to introduce a dark mode, then it would be difficult to dynamically update those hardcoded values in an easy and efficient manner. With design tokens, we provide dark mode tokens that we can target using data attributes within our components.

If you would like to see a working demo, we have two sample repos for engineers to get an up-close look.

Streamlined Designer Developer Handoff

Currently, we do not have consistent naming conventions between designers and developers. This creates the space for miscommunication and can add room for error to the handoff process. This issue becomes evident when we consider state colors. In our current implementation of a pressed state, we use a SASS transform function to darken the color by a percentage.

We do not have an exact value at our disposal, and we would need to work out what value the transform outputs. An ideal scenario is to have a constant HEX value for the pressed state, so there is no ambiguity between the designers and developers. Luckily, we have this with DLS v7 design tokens! If a designer hands off a primary button prototype with a pressed state, they would use a design token called button-primary-background-color-pressed. Then, the developers will know exactly what HEX value to use because they can reference the design token by name.

What the DLS is Releasing

Design Dictionary

First, we have the DLS design dictionary, which can be found in the colossus-tokens repo. It is key that the tokens are stored in a central, highly visible location. This is the single source of truth to understand what tokens are offered and what their values are. Any modifications to our design tokens will be made here, and the changes will cascade down to applications that consume our tokens.

To cover a variety of tech stacks, the tokens must be implementation agnostic. They are stored as JSON and converted to JavaScript variables, CSS variables, or SASS variables during our build. The tokens can be published to a CDN (Content Delivery Network) (CDaaS for internal use) or NPM.

Graph Showing How Tokens Are Consumed

The above screenshot shows the different ways our tokens can be consumed.

Two informative articles are Naming Tokens in a Design System and Building Better Products with the Design Token Pipeline. We will include some of the highlights from the articles below as we give an overview of two concepts: Option Tokens and Decision Tokens.

Option Tokens

Option tokens are all the available values within a design system and can include colors, fonts, and spacing, etc. It is the only place where we store raw values, like 10px, and they are not meant to be used directly. It is intended to be referenced by the decision tokens. The naming does not suggest how it should be used. For example, color-neutral-gray-100 does not indicate where or how to use this design token. The benefit of option tokens is that it is easier to add new component into a design system. We just pick the option tokens to use. Option tokens set the foundation for our design system.

The option token tier includes base tokens and semantic tokens.

Base Tokens

These tokens store the raw values and are at the core of the design system. They adhere to the option tokens rules by not providing context. In the diagram below, color-utility-bright-blue-500 is a base token. From the name, all you can extrapolate is that the token is some color of blue. It does not tell you where or how you should use it. These are not intended for public use, meaning that consumers should not directly reference these tokens. Instead, they should use semantic tokens.

Semantic Tokens

These tokens reference the base tokens and their name provides more context to describe the intended use. These will be used frequently throughout an application. In the diagram, the color-brand-primary name does not tell you what color it is, but it does indicate that this token is the main color of a particular brand. For the default American Express styling, this would be our bright blue. However, if we created a custom theme for the Gold card, then the color-brand-primary could be a gold color.

Decision Tokens

Decision tokens contrast option tokens because they do indicate the exact context in which the token should be used. It references option tokens and will never store a raw value. Its purpose is to apply option tokens to a specific context. For example, if we want to make a primary button the American Express blue color, we can create a component token called button-primary-background-color. Notice how the token name suggests how and in what context to use the token; you could deduce that this token is meant for the background color of the primary button variant. The component token will reference the semantic token color-brand-primary, which references another base token color-utility-bright-blue-500, which stores the raw value of #006FCF. Although the cascading nature may seem confusing at first, it provides some key benefits.

First, we can avoid mixing up values with the component tokens compared to using raw values. Because the token names indicate its use, we can spot errors more easily. To pull an example from the “Building Better Products with Design Tokens Pipeline” article, if I am adding padding-bottom to a button and accidentally use the component token button-padding-top, then that mistake is easier to spot.

Second, by restricting component tokens to a specific context, we can update values without interfering with other styles in other components. If I only wanted to update the button styles without changing the checkbox styles, then I can do that with design tokens.

The decision token tier includes general tokens and component tokens.

General Tokens

These tokens do not suggest what component to use it in, but they do indicate the CSS property it is meant to style. For example, the background-color token can be used to style the background-color for a multitude of elements.

Component Tokens

Unlike the general tokens, component tokens do suggest which component to use it in. The button-primary-background-color has a narrower use case than the background-color general token. For example, we would not expect to use button-primary-background-color to style an input. This allows us to restrict styles changes to a single component, which makes updates easier.

Graph showing naming hierarchy for option and decision tokens

The above screenshot shows the naming hierarchy for option and decision tokens.

JSON

The JSON format is important because it allows us to maintain an organized hierarchy of tokens. This makes maintenance easier for the DLS team while letting designers and developers create and customize themes more easily. The tokens can also reference other tokens in the JSON file, so if some token changes, we can rest assured that all the dependent tokens will also get updated. We run the build step and the token gets generated automatically for all platforms.

CSS Variables

A key pillar in all of this is the use of CSS variables. As a quick review, CSS variables let you put values in variables. When you declare a variable, you prefix the name with a double dash, then you put the value. Once you declare a variable, you can then reference each variable with the var function.

Declaring a variable example

Designers: Using Design Tokens

For designers, we can export to sketch palettes. The workflow will become more streamlined because designers do not need to dig through design documentation to find style values when designing a custom component. If they are building something that acts like an input, they can easily track down the input tokens.

During the designer-developer handoff, the designer just tells the developer which token to use and eliminates the need for hardcoding when creating DLS compliant custom components. What if the value of the token changes in the future? You will be relieved to hear that the only work required is just upgrading to the newest version of the DLS-tokens package.

Developers: Using Design Tokens & Making Custom Themes

The DLS created two demo applications for our users to have a working example of design tokens.

You will find example code and more detailed documentation in the README files. In each example, we show:

  • How to create a section with custom theming.
  • How to create a custom component to use the DLS design tokens.
  • How to toggle between light, dark, and system mode.

Acknowledgements

I want to thank my team member, Lucas Grinspan, for graciously allowing me to borrow content from his DevCon presentation for this blog post. If you would like to watch his talk, check it out the recording.

Feedback

We want to hear from you! Are you excited about design tokens or have questions of the impact on your team’s work? Let us know on slack or by emailing dls@aexp.com.

Questions?

Connect with the DLS Team on Slack or by email.

Resources

Check out additional resources.