Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Design tokens in maps

Design tokens are the named basic values of a design: colours, spacing steps, font sizes, radii. Designers and developers agree on the names — primary, space 2, radius md — and the code uses only these names, never random values. In Sass tokens are naturally stored in maps.

A tokens file

Create styles/abstracts/_tokens.scss with three groups of tokens:

// styles/abstracts/_tokens.scss
$colors: (
  "primary": #2563eb,
  "surface": #ffffff,
  "text": #1f2937,
  "muted": #6b7280,
);
 
$space: (
  1: 4px,
  2: 8px,
  3: 16px,
  4: 32px,
);
 
$radius: (
  "sm": 4px,
  "md": 8px,
);

The spacing keys are numbers: 1, 2, 3. Number keys are written without quotes.

Functions for reading tokens

Writing map.get(tokens.$colors, "primary") every time is long. Small functions make it short and check the name. Create styles/abstracts/_functions.scss:

// styles/abstracts/_functions.scss
@use "sass:map";
@use "tokens";
 
@function color($name) {
  @if not map.has-key(tokens.$colors, $name) {
    @error "Unknown colour token '#{$name}'.";
  }
  @return map.get(tokens.$colors, $name);
}
 
@function space($step) {
  @return map.get(tokens.$space, $step);
}
 
@function radius($name) {
  @return map.get(tokens.$radius, $name);
}

Using tokens in a component

The card takes all its values from tokens:

// styles/components/_cards.scss
@use "../abstracts/functions" as fn;
 
.card {
  padding: fn.space(3);
  color: fn.color("text");
  background: fn.color("surface");
  border: 1px solid fn.color("muted");
  border-radius: fn.radius("md");
}
// styles/main.scss
@use "components/cards";
.card {
  padding: 16px;
  color: #1f2937;
  background: #ffffff;
  border: 1px solid #6b7280;
  border-radius: 8px;
}
<style>
  .card {
    padding: 16px;
    color: #1f2937;
    background: #ffffff;
    border: 1px solid #6b7280;
    border-radius: 8px;
  }
</style>
 
<div class="card">The card's values come from tokens</div>

If the designer changes space 3 from 16px to 20px, you edit one line in _tokens.scss, and every card, form and header updates.

Generating classes from tokens

The same maps feed utility classes, so the classes always match the tokens:

// styles/utilities/_spacing.scss
@use "../abstracts/tokens";
 
@each $step, $value in tokens.$space {
  .p-#{$step} {
    padding: $value;
  }
}
// styles/main.scss
@use "utilities/spacing";
.p-1 {
  padding: 4px;
}
 
.p-2 {
  padding: 8px;
}
 
.p-3 {
  padding: 16px;
}
 
.p-4 {
  padding: 32px;
}

Why not plain variables

Separate variablesTokens in a map
$space-1, $space-2, $space-3One map $space
A loop over them is impossible@each goes through all tokens
A typo is an Undefined variable errorA typo is caught by @error in the function
Easy for a small projectScales to dozens of values

Common mistake

Do not bypass the tokens "just this once" with a value like padding: 15px. One exception becomes ten, and the next design change misses them. If a value is missing, add a token for it — or ask whether the nearest existing step will do.

Thanks for reading!

Donate to the site — we work hard for you.