Introduction
Blog
Timeline

A Beginner's Guide to Design Tokens.

thumbnail

Introduction

If you've ever worked in a company that offers multiple products, each product having its own landing page or an entire website dedicated to it, the greatest challenge one has to face is ensuring consistency.

While these pages may differ in design and functionality, they still need to maintain a similar look that aligns with the company's brand identity.

Take Google as an example: Google.com, Gmail, Google Meet, Google Docs and even Google Cloud. While each of these products serves a different purpose and has unique use cases, they all maintain a consistent look and feel that is unique to Google's brand identity. This consistency is achieved through a unified design system made up of carefully selected visual elements like colors, typography and icons--often in the form of Design tokens.

A simple button component

Before we move on to solution, let me explain the problem while building a simple button component.

Its pretty common for buttons to have a prefix and/or suffix prop - space for icons before or after the button text. When designing our button component we decided to use 8px padding on both the left and right sides. However, we chose 3px for the space between the prefix and text and 5px between the text and the suffix, simply because they looked "better".

thumbnail

Although this approach might seem fine in isolation, it introduces inconsistencies across the broader design.

Why is this a problem?

When the button component is paired with other components built using the same philosophy - prioritizing visual appeal without considering overall cohesion, the result is a disruption in visual harmony.

thumbnail

At first glance, the problem may seem exaggerated, but as a project grows, the number of design decisions increase significantly .The real problem lies in having the freedom to choose from an unlimited range of values for each specific use case.

By establishing a system that enforces a predefined set of values, you reduce the likelihood of errors and streamline decision-making.

If you've ever used TailwindCSS , you might have noticed that all of the margin, padding and space values adhere to a structured system:

  1. They are all multiples of 4 (e.g. 4px, 8px, 12px)
  2. They follow a specific formula, meaning that even though 60px is technically a multiple of 4px, It is not part of their system.

The concept remains the same, elimination of arbitrary choices.

Embracing Constraint-Based Design

At its core, Constraint-based design philosophy suggests that by limiting yourself to a predefined set of carefully chosen values, you:

  1. Reduce design inconsistencies
  2. Streamline decision-making
  3. Make better design choices

Instead of relying on intuition alone, we can setup a structured spacing scale/system with predefined values for padding, margin and space between different elements. These values should follow a strict scaling formula allowing increments like 2px, 4px or 6px and discourage the use of arbitrary values like 7px and 13px.

For example:

thumbnail

Once we've standardize spacing, we can extend the same principal to colors, shadows, border radii and typography.

thumbnail

thumbnail

thumbnail

The values that we've established so far are called design tokens. These serve as the building blocks of a design system and are a way to store and manage design decisions in a consistent, reusable format, typically as variables.

These tokens represent all of the atomic values that make up your design such as color codes, font sizes, text sizes, shadows and more. By using design tokens, these values can be easily maintained and updated across all products, ensuring uniformity.

Design tokens are in direct contrast to "Magic Values". A magic value refers to any arbitrary value used in the design, often for the sake of aesthetics, without any regards to the broader design language of the company.

Using them in your code-base is as simple as creating a CSS file in your code-base called varibles.css and setting the tokens you've selected so far as CSS variables. For example:

  --text-sm: 0.875rem;
  --text-base: 1rem;
  --text-lg: 1.125rem;
  ...

  --radius-xs: 0.125rem;
  --radius-sm: 0.25rem;
  --radius-md: 0.375rem;
  ...

  --color-blue-50: oklch(0.985 0 0);
  --color-blue-100: oklch(0.97 0 0);
  --color-blue-200: oklch(0.922 0 0);

Once the tokens are defined, import variables.css into your project's main entry point. Instead of hard-coding values, use the predefined tokens in your styles like so:

.button{
   font-size: var(--text-base);
   border-radius: var(--raidus-md);
}

This significantly accelerate the prototyping process by providing a structured approach to styling.

Consider a button component where we need to define a background color:

  1. Default state => Base shade of blue
  2. Hover state => A lighter shade of blue
  3. Pressed state => A darker shade of blue

If we've already setup our color tokens:

  blue-50: oklch(0.97 0.014 254.604);
  blue-100: oklch(0.932 0.032 255.585);
  blue-200: oklch(0.882 0.059 254.128);
  blue-300: oklch(0.809 0.105 251.813);
  blue-400: oklch(0.707 0.165 254.624);
  blue-500: oklch(0.623 0.214 259.815);
  blue-600: oklch(0.546 0.245 262.881);
  blue-700: oklch(0.488 0.243 264.376);
  blue-800: oklch(0.424 0.199 265.638);
  blue-900: oklch(0.379 0.146 265.522);
  blue-950: oklch(0.282 0.091 267.935);

where the higher suffix value signifies a darker shade of blue, instead of spending time finding shades of blue, we can set the background color to be:

  1. Default => blue-500
  2. Hover => blue-400
  3. Pressed => blue-600

In code, we can have something like this:

button{
  background-color: var(--blue-500);
}

button:hover{
  background-color: var(--blue-400);
}

button:active{
  background-color: var(--blue-600);
}

By introducing design tokens to our codebase, not only have we simplified our design process, we've also improved maintainability.

If, at any point in the future, we decide to change the underlying value of our base blue color, we do not need to hunt down and manually change every instance it was used. Instead, we can simply update the variables.css file and the changes will automatically apply across the entire project.

By embracing design tokens and constraint-based design, we eliminate inconsistencies, improve scalability, and streamline our design decisions.

References material and further Reading

  1. Adobe's guide on design tokens
  2. Introduction to constraint based design systems
  3. Constraint based design