Design tokens, in thirteen formats
On this page
Every color, typeface, size, breakpoint, duration, radius, shadow and theme in your manual is also a file a build can read: 13 formats, two archives, and an API address that serves the same values.
What a design token is here
WhereDashboard, Export tokens
A token is a name and a value, taken from a block you already filled in. You enter nothing twice for the export. Prose, rules, do and don't pairs and images are not tokens. The page and its files need the permission View the brand manual, which every built in role has, and no plan holds the export back.
Which manual the page reads
The page reads the brand's primary manual, every section of it, published or not. So what a reader sees and what you download can differ while you are still working. For any other manual, read its tokens over the API at its own address. See Design tokens in the API (opens in a new tab).
Which block fills which group
Nine blocks produce tokens. Each fills one group, and the group name is the folder name in the archive.
| Block | Group | What it produces |
|---|---|---|
| Color | colors | One token per swatch, plus the eleven tints and shades when the block shows them. |
| Typography | typography | One token per typeface, named after its usage. |
| Type scale | type-scale | Every step: a size, a line height, and a tracking when it is not zero. |
| Spacing scale | spacing | Every step of the scale, as a length. |
| Grid and layout | breakpoints | The named breakpoints. Columns, gutters and margins are not tokens. |
| Motion | motion | The durations and the easing curves, as two groups. |
| Corner radius | radius | Each named radius as CSS. A full radius is written as 9999px. |
| Elevation | elevation | Each level as a box-shadow value. |
| Themes | themes | One group per theme, holding the role colors that theme sets. |
Every other block reaches brand-manual.md in the brand kit and the manual's JSON over the API, and no token file.
When a manual has several blocks of one kind
Color, Typography, Grid and layout, Motion, Corner radius, Elevation and Themes are collected from every block of that kind, in section order: two Color blocks make one palette. Spacing scales are merged and repeats dropped. The type scale is the exception: the first Type scale block wins and a second does not replace it.
How a value becomes a named token
A token name is the label lowercased, with anything that is not a letter or a digit turned into a hyphen and the hyphens trimmed off both ends. Deep sea 40 becomes deep-sea-40.
color-1, color-2. A repeated name is numbered within its group, so the second is primary-2. Same for typefaces, breakpoints, durations, easings and themes.font-heading and the family name is the value. No usage gives font, then font-2. No family name means no token.spacing-2-5, and 2_5 in the code formats. Bare digits get px; a step with a unit is left as it is.What is left out
A color whose hex cannot be read is in no token file and in no swatch group. A breakpoint, duration or easing with an empty value is not a token. An empty theme role is dropped, and a theme with no readable color is not exported at all.
The page itself
WhereDashboard, Export tokens
Eight tiles count what was collected. The tabs switch the panel between the 13 formats, Copy takes the whole file, and Download saves it under that format's name, such as _tokens.scss. The inventory below the panel lists the export group by group, with every color shown in HEX, RGB, HSL and CMYK and rated for contrast on white. With nothing to export, the page names the nine blocks that produce tokens and links to the editor.
The 13 formats
Every format is written from the same collected tokens and differs only in what it can express. The last column is what each file carries. The samples below are one brand with one of everything.
| Format | File | What it carries |
|---|---|---|
| CSS | tokens.css | All 9 groups |
| SCSS | _tokens.scss | All 9 groups |
| Less | tokens.less | All 9 groups |
| JS and TS | tokens.ts | All 9 groups |
| Tailwind | tailwind.tokens.js | All 9 groups |
| JSON | tokens.json | All 9 groups |
| W3C Tokens | tokens.w3c.json | All 9 groups |
| Style Dictionary | tokens.sd.json | Color, Typography, Spacing scale, Grid and layout, Motion and Themes |
| SwiftUI | BrandColors.swift | Color |
| Compose | Brand.kt | Color and Spacing scale |
| Flutter | brand.dart | Color and Spacing scale |
| Android XML | colors.xml | Color and Spacing scale |
| CSV | colors.csv | Color |
The five web files
CSS
Custom properties under :root. Each color brings an -rgb and an -hsl companion, so a rule can set an alpha. Each theme is a block keyed by a data attribute.
:root {
--color-primary: #c2542c;
--color-primary-rgb: 194, 84, 44;
--color-primary-hsl: 16, 63%, 47%;
--font-heading: "Inter";
--text-md: 1rem;
--leading-md: 1.5;
--text-lg: 1.25rem;
--leading-lg: 1.42;
--tracking-lg: -0.01em;
--spacing-8: 8px;
--spacing-16: 16px;
--breakpoint-md: 768px;
--duration-fast: 150ms;
--easing-standard: cubic-bezier(0.2, 0, 0, 1);
--radius-md: 8px;
--shadow-2: 0 2px 8px -1px rgba(0, 0, 0, 0.12);
}
[data-theme="dark"] {
--theme-background: #111111;
--theme-text: #f5f5f5;
}SCSS
Sass variables, with the colors carrying an -rgb list. A theme role is a flat variable named after the theme and the role.
$color-primary: #c2542c;
$color-primary-rgb: (194, 84, 44);
$font-heading: "Inter";
$text-md: 1rem;
$leading-md: 1.5;
$text-lg: 1.25rem;
$leading-lg: 1.42;
$spacing-8: 8px;
$spacing-16: 16px;
$breakpoint-md: 768px;
$duration-fast: 150ms;
$easing-standard: cubic-bezier(0.2, 0, 0, 1);
$radius-md: 8px;
$shadow-2: 0 2px 8px -1px rgba(0, 0, 0, 0.12);
$theme-dark-background: #111111;
$theme-dark-text: #f5f5f5;Less
One @ variable per token. No color companions, no tints and shades.
@color-primary: #c2542c;
@font-heading: "Inter";
@spacing-8: 8px;
@spacing-16: 16px;
@breakpoint-md: 768px;
@duration-fast: 150ms;
@easing-standard: cubic-bezier(0.2, 0, 0, 1);
@radius-md: 8px;
@shadow-2: 0 2px 8px -1px rgba(0, 0, 0, 0.12);
@theme-dark-background: #111111;
@theme-dark-text: #f5f5f5;
@text-md: 1rem;
@leading-md: 1.5;
@text-lg: 1.25rem;
@leading-lg: 1.42;Tailwind
A config fragment under theme.extend, so every token arrives as a utility class. It fills colors, fontFamily, spacing, screens, transitionDuration, transitionTimingFunction, fontSize, borderRadius and boxShadow. Theme roles nest under colors, so a role is a class such as bg-theme-dark-background.
/** Stylehub brand tokens */
module.exports = {
theme: {
extend: {
colors: {
"primary": "#c2542c",
"theme-dark": {
"background": "#111111",
"text": "#f5f5f5",
},
},
fontFamily: {
"heading": ["Inter", "sans-serif"],
},
spacing: {
"8": "8px",
"16": "16px",
},
screens: {
"md": "768px",
},
transitionDuration: {
"fast": "150ms",
},
transitionTimingFunction: {
"standard": "cubic-bezier(0.2, 0, 0, 1)",
},
fontSize: {
"md": ["1rem", { lineHeight: "1.5" }],
"lg": ["1.25rem", { lineHeight: "1.42" }],
},
borderRadius: {
"md": "8px",
},
boxShadow: {
"2": "0 2px 8px -1px rgba(0, 0, 0, 0.12)",
},
},
},
};JS and TS
A module of exported objects for JavaScript and TypeScript. Keys are camel cased and quoted. Spacing keys carry an s in front of the number. An empty group is still exported as an empty object.
// Stylehub brand tokens
export const colors = {
"primary": "#c2542c",
} as const;
export const fonts = {
"heading": "Inter",
} as const;
export const spacing = {
"s8": "8px",
"s16": "16px",
} as const;
export const breakpoints = {
"md": "768px",
} as const;
export const durations = {
"fast": "150ms",
} as const;
export const easings = {
"standard": "cubic-bezier(0.2, 0, 0, 1)",
} as const;
export const radii = {
"md": "8px",
} as const;
export const shadows = {
"2": "0 2px 8px -1px rgba(0, 0, 0, 0.12)",
} as const;
export const fontSizes = {
"md": "1rem",
"lg": "1.25rem",
} as const;
export const themes = {
"darkBackground": "#111111",
"darkText": "#f5f5f5",
} as const;The three JSON documents
JSON
The product's own shape, and the only file with all four color notations at once: hex, rgb, hsl and cmyk, with the usage note. Tints and shades sit under colorScale.
{
"color": {
"primary": {
"hex": "#c2542c",
"rgb": "rgb(194, 84, 44)",
"hsl": "hsl(16, 63%, 47%)",
"cmyk": "cmyk(0, 57, 77, 24)",
"usage": "Buttons and links"
}
},
"colorScale": {},
"font": {
"heading": {
"value": "Inter"
}
},
"fontSize": {
"md": {
"value": "1rem",
"lineHeight": 1.5,
"tracking": "0em"
},
"lg": {
"value": "1.25rem",
"lineHeight": 1.42,
"tracking": "-0.01em"
}
},
"spacing": {
"8": {
"value": "8px"
},
"16": {
"value": "16px"
}
},
"breakpoint": {
"md": {
"value": "768px"
}
},
"duration": {
"fast": {
"value": "150ms"
}
},
"easing": {
"standard": {
"value": "cubic-bezier(0.2, 0, 0, 1)"
}
},
"radius": {
"md": {
"value": "8px"
}
},
"shadow": {
"2": {
"value": "0 2px 8px -1px rgba(0, 0, 0, 0.12)"
}
},
"theme": {
"dark": {
"background": "#111111",
"text": "#f5f5f5"
}
}
}W3C Tokens
The W3C design tokens shape: every entry is a $value with a $type. Spacing and breakpoints share the dimension group, with the breakpoints prefixed. This is the document the API serves.
{
"color": {
"primary": {
"$value": "#c2542c",
"$type": "color"
}
},
"dimension": {
"8": {
"$value": "8px",
"$type": "dimension"
},
"16": {
"$value": "16px",
"$type": "dimension"
},
"breakpoint-md": {
"$value": "768px",
"$type": "dimension"
}
},
"fontFamily": {
"heading": {
"$value": "Inter",
"$type": "fontFamily"
}
},
"fontSize": {
"md": {
"$value": "1rem",
"$type": "dimension"
},
"lg": {
"$value": "1.25rem",
"$type": "dimension"
}
},
"duration": {
"fast": {
"$value": "150ms",
"$type": "duration"
}
},
"cubicBezier": {
"standard": {
"$value": "cubic-bezier(0.2, 0, 0, 1)",
"$type": "cubicBezier"
}
},
"radius": {
"md": {
"$value": "8px",
"$type": "dimension"
}
},
"shadow": {
"2": {
"$value": "0 2px 8px -1px rgba(0, 0, 0, 0.12)",
"$type": "shadow"
}
},
"theme": {
"dark": {
"background": {
"$value": "#111111",
"$type": "color"
},
"text": {
"$value": "#f5f5f5",
"$type": "color"
}
}
}
}Style Dictionary
The source format a Style Dictionary build expects. Families sit under font.family rather than under size. It carries color, typography, spacing scale, grid and layout, motion and themes and nothing else: no type scale, no radii, no shadows.
{
"color": {
"primary": {
"value": "#c2542c"
}
},
"font": {
"family": {
"heading": {
"value": "Inter"
}
}
},
"size": {
"spacing": {
"8": {
"value": "8px"
},
"16": {
"value": "16px"
}
}
},
"breakpoint": {
"md": {
"value": "768px"
}
},
"motion": {
"duration": {
"fast": {
"value": "150ms"
}
},
"easing": {
"standard": {
"value": "cubic-bezier(0.2, 0, 0, 1)"
}
}
},
"theme": {
"dark": {
"background": {
"value": "#111111"
},
"text": {
"value": "#f5f5f5"
}
}
}
}The four platform files
These are for an app rather than a page. Colors in all four, spacing in three, nothing else.
SwiftUI
Its own enum of colors, each as red, green and blue between 0 and 1, rather than an extension of Color. A name that starts with a digit is prefixed, and a Swift keyword has Color appended.
import SwiftUI
enum BrandColors {
static let primary = Color(red: 0.761, green: 0.329, blue: 0.173)
}Compose
Kotlin objects for Android: BrandColors as Color(0xFF...) and BrandSpacing in dp. The package line at the top is a placeholder, so change it to yours.
package com.yourcompany.brand
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
object BrandColors {
val Primary = Color(0xFFC2542C)
}
object BrandSpacing {
val S8 = 8.dp
val S16 = 16.dp
}Flutter
The same two classes in Dart, with spacing as doubles.
import 'package:flutter/material.dart';
class BrandColors {
static const primary = Color(0xFFC2542C);
}
class BrandSpacing {
static const s8 = 8.0;
static const s16 = 16.0;
}Android XML
A resource file for a project that is not on Compose. Hyphens in a name become underscores, and spacing is written in dp. Colors and dimensions share one resources element.
<?xml version="1.0" encoding="utf-8"?>
<!-- res/values/colors.xml -->
<resources>
<color name="primary">#c2542c</color>
<dimen name="spacing_8">8dp</dimen>
<dimen name="spacing_16">16dp</dimen>
</resources>The CSV
The palette as a spreadsheet: one header row, then a row per color with name, hex, rgb, hsl, cmyk and usage. Send it to a printer or to anyone who wants a plain list.
name,hex,rgb,hsl,cmyk,usage
"primary","#c2542c","rgb(194, 84, 44)","hsl(16, 63%, 47%)","cmyk(0, 57, 77, 24)","Buttons and links"A cell is never a formula
Every format at once
WhereDashboard, Export tokens, Download all formats (.zip)
One archive with all 13 files at the root, the Adobe swatch file beside them when the manual has at least one color, and under by-block one folder per group that produced something. Each of those folders holds that group alone as CSS, JSON, W3C Tokens and Tailwind. Take one folder and leave the rest.
tokens.css
_tokens.scss
tokens.less
tokens.ts
tailwind.tokens.js
tokens.json
tokens.w3c.json
tokens.sd.json
BrandColors.swift
Brand.kt
brand.dart
colors.xml
colors.csv
colors.ase
by-block/colors/tokens.css
by-block/colors/tokens.json
by-block/colors/tokens.w3c.json
by-block/colors/tailwind.tokens.js
by-block/typography/
by-block/type-scale/
by-block/spacing/
by-block/breakpoints/
by-block/motion/
by-block/radius/
by-block/elevation/
by-block/themes/The file is named after the manual's slug, for example acme-tokens.zip. A manual with no slug is called brand. A manual with no tokens shows neither download button.
The Adobe swatch file
WhereDashboard, Export tokens, Download .ase (Adobe)
Download .ase (Adobe) writes an Adobe Swatch Exchange file for Illustrator, Photoshop and InDesign, named after the manual slug as acme-colors.ase. The button appears only when the manual has at least one readable color.
The first group is the palette, named after the manual, with each swatch under the color name as it was typed. A swatch left with no name is numbered by its position. Then comes one group per scale, named Primary tints and shades after the color it belongs to, with the eleven swatches inside. Only a Color block that shows its tints and shades produces one. Every swatch is RGB and global, so changing it repaints everything that uses it.
The same file is inside both archives: colors.ase in the all formats download and tokens/colors.ase in the brand kit. How the eleven steps are computed is in the Color article, under tints and shades.
The full brand kit
WhereDashboard, Export tokens, Download .zip
The kit is the other archive on the page: the tokens, a readable copy of the manual, and the asset library grouped by category. Send it to an agency that needs the brand rather than to a build that needs the values.
tokens.css, tokens.json, colors.csv, tokens.w3c.json and tailwind.tokens.js, with colors.ase beside them when there are colors. For all 13, use the other archive.README.txt says so.The kit needs the files permission too
A kit holds just under four gigabytes of files, and a larger library is refused with a message naming both sizes. A file that could not be read is written empty and listed in _missing-files.txt at the end of the archive.
Reading the tokens instead of downloading them
The read only API serves the same W3C document as tokens.w3c.json, at one address per published manual. Use it so your build does not depend on a download. The exact address of every published manual is on the API page (opens in a new tab) of the dashboard.
curl -sS https://stylehub.cloud/api/v1/manuals/acme/tokens.json -o tokens.json- A public or unlisted manual needs no token. Any other visibility takes an API token of that brand. Tokens are made and revoked on the API page, which needs the permission Edit workspace settings and domains. See Authentication (opens in a new tab).
- Keep the token secret. Do not put it in a public page: it reads every manual the brand has.
- Calls a minute are limited by the plan of the brand being read, and counted per caller. See Rate limits (opens in a new tab), and Caching (opens in a new tab) for how to ask only when something changed.
The API serves the published manual
Worked examples in PHP, Node, Python and C sharp are in the API examples (opens in a new tab), and the exact contract of every address is in the API documentation (opens in a new tab).
When a token you expected is missing
Where to go next
- The export page (opens in a new tab) to take the files.
- Color and Typography for the blocks behind the two largest groups.
- The manual as a PDF, the other export.
- Design tokens in the API (opens in a new tab) for a build that fetches the tokens on every run.
Still stuck? Write to hello@stylehub.cloud and say which page you were on.