Design Token Boilerplate

Evolving the outcomes of multiple projects & patterns into a boilerplate

NOTE

This is a work in progress. I'm writing it in public and updating it as I continue writing.

I've been wanting to develop my boilerplate for a long while now. I'm at a point where I keep reinventing and trying to figure out the things and would rather work from a boilerplate to decrease the amount of decisions I make each project onset.

Foundations

Naming is one of the most important things of a design system. It needs to be consistent, but flexible; declarative, but not prescriptive.

These days, primitives is a relatively standard nomenclature for this group of tokens. I, personally, don't like that word to define them. There are too many definitions that can create ambiguity or mis-frame their import.

Collectively, I like to call it the foundation. These tokens are what everything's built on—adding meaning as compositions emerge by adding style to semantic structure. These also need to be the smallest, simplest variable names for ease of re-use and development (when getting much farther along the system creation, token names tend to get lengthy). I'm one for typographpical poetry of length, so if the foundations are the smallest units with the shortest names, they're quickly identifiable, understandable, and rememberable.

Constants

These are ones that I'll always use, but are singular in words:

  • --paper for white, and developing tints;
  • --ink for black, and developing shades;
  • --ash for gray, and developing tones.

Prefixes

A prefix is something at the beginning. In grammar, these are remixable, contextual preambles like re-, con-, or pre-.

These are the first words of my boilerplate's token set:

  • --font- for font-family;
  • --scale- for font-size;
  • --stretch for font-width;
  • --style- for font-style;
  • --weight- for font-weight;
  • --tracking- for letter-spacing;
  • --stroke- for border-width;
  • --leading- for line-height;
  • --opacity- for...well, opacity values;
  • --palette- for base colors;
  • --duration- for transition and animation timings;
  • --radii- for border-radius (and the fun of using two i's in a row);
  • --space- for padding, margin, and gap;
  • --measure- for max-width and typographic line-length;
  • --layer- for z-index;
  • --ratio- for aspect-ratio;
  • --prominence- for box-shadow;

Values & Gradients

For some of these, I use explicit values. For others, semantic gradients.

It depends on how the token's purpose and relationship with it's property counterpart.

Typography

font

Each of these are the typical ones I come across in most settings.

They're also grounded in generic font family naming, just a limited set. In total, there're 12 potential generic font families to use, but these four tend to cover most of my use cases (and identity systems).

:root{
  --font-sans: $stack, sans;
  --font-serif: $stack, serif;
  --font-mono: $stack, mono;
  --font-hand: $stack, cursive;

weight

Most of my design decisions boil down to typographic history and practical use.

These are, generally, named for their typical weight naming scheme, respectively mapped to their default weights. Because variable fonts provide a plethora of potential values, having these as tokens rather than defaults enables depth of polish.

:root{
  --weight-thin: 100;
  --weight-extralight: 200;
  --weight-light: 300;
  --weight-regular: 400;
  --weight-medium: 500;
  --weight-semibold: 600;
  --weight-bold: 700;
  --weight-extrabold: 800;
  --weight-black: 900;

stretch

Like weight, this has default values but can be set differently in variable font situations.

These map to another typical font design for typeface widths, developed over the centuries to give semantic name to width.

:root{
  --stretch-ultra-con: ultra-condensed; /* 50% width */
  --stretch-extra-con: extra-condensed;  /* 62.5% width */
  --stretch-con: condensed;  /* 75% width */
  --stretch-semi-con: semi-condensed;  /* 87.5% width */
  --stretch-reg: normal;  /* 100% width */
  --stretch-semi-exp: semi-expanded;  /* 112.5% width */
  --stretch-exp: expanded;  /* 125% width */
  --stretch-extra-exp: extra-expanded;  /* 150% width */
  --stretch-ultra-exp: ultra-expanded;  /* 200% width */

measure

Measure is the fancy typography word for length of a line of text, specifically from the left to right edges of a text block. In terms of reading length, it's good to aim for 45–85 characters per line, inclusive of spaces.

The primary aspects that influence measure are: size of the type and size of its container (be it block, like a section, or a unit, like a paragraph).

:root{
  --measure-xxs: 25ch;
  --measure-xs: 35ch;
  --measure-sm: 45ch ;
  --measure-md:55ch ;
  --measure-lg: 65ch;
  --measure-xl: 75ch ;
  --measure-xxl: 85ch;

scale

  • --scale- for font-size;

style

  • --style- for font-style;

tracking

  • --tracking- for letter-spacing;

leading

  • --leading- for line-height;

Color

opacity

  • --opacity- for...well, opacity values;

    palette

  • --palette- for base colors;

    duration

  • --duration- for transition and animation timings;

Block

radii

  • --radii- for border-radius (and the fun of using two i's in a row);

    ratio

  • --ratio- for aspect-ratio;

    stroke

  • --stroke- for border-width;

    space

  • --space- for padding, margin, and gap;

    prominence

  • --prominence- for box-shadow

    layer

  • --layer- for z-index;

Semantic Gradients

I've written about semantic gradients before, making lists, and compiling them. They're these cool relational word ladders that transition from one end of a spectrum to another.

I prefer these over numbering systems—100,200,300,400,... or 10,20,30,40,...—because words. I find the lack of explicit and definite number scale provides room for play, interpretation, but also ways of individualizing the scale to act as a trap street—a maker's mark to detect copyright violations (and, as is the case these days, detecting content was used as fodder for scrapers and large language model training).

Each of the prefixes, above, come with default semantics—gradient or otherwise. I'm thematically grouping them for ease of reading.