Suzanne Sallaj

Design systems · Stage 4 of 6 · Writing the colors into a design system

Writing the colors into a design system

By Suzanne Sallaj

· 30 min read · design system series, part 4

Two lessons on writing the color roles into Figma, a repository, and the rules page.

You are here

In this article, we will cover the following:

  1. Let a tool write the files
  2. Write the rules down

These are lessons 8 and 9 of the twelve it takes to build a design system. Lesson 1 was the first article, Introduction to design tokens. Lessons 2 to 5 were the second, Choosing the color roles. Lessons 6 and 7 were the third, Expanding on color roles. Lessons 10 to 12 come in the next article. The full list is below, each with an example.

Part one · Make the systemLessons 1 to 7
Lessons 1 to 7Covered in the first three articlesLearn the token vocabulary · Decide where the colors are kept · List the purposes · Ask the three questions and count · Choose one color for each family · Choose a shade for each part · Organize for documentation
Part two · Make sure it gets usedLessons 8 and 9 shown
8
Let a tool write the filesa tool does it

A program turns the names into the files the website uses. Nobody types them by hand.

ExampleYou change the green in one place. The tool rewrites every file that uses it.
Lesson 8
9
Write the rules downwriting

Describe each name and when to use it, so that people and tools can look it up.

ExampleShopify's Polaris documentation is this step. The role descriptions in this series came from it; the color values came from Shopify's token files.
Lesson 9
Lessons 10 to 12Covered in the fifth articleBuild a checker · Change the existing screens over · Human check before release

Article 3 ended with lesson 7: six choices for the success role, written down in one table by hand. The color role, the part, the green, and what it was checked against. This article takes that table and writes it into Figma, by hand and with an AI agent, then lets a program write the files from it.

Writing the list

Two ways to write it: by hand, and with an AI agent. Both start after lesson 6, with the greens already chosen. What follows is writing them down, in two steps: fill out the list, then write the list into Figma.

By hand

Step 1 · Fill out the list

By this point the role is chosen, in article 2, its family is made, in article 3, and the greens it uses have their loudness names from article 3's 5th step. Start with a blank list for the role: a row of sixteen boxes for the family at the top, then five columns: the color role, the part, the meaning, dark, and sits on. The parts are the same for every role. Most design systems give each color role these six: a background, a border, an icon, the words, a filled background for small solid shapes such as a badge, and the words on that filled background. The last row is for anything extra your screens need.

TipIf you're a visual learner, draw the component first, such as the "Saved" message and its badge from article 3, and label each of its parts. It is not needed to fill the list, but with the drawing in front of you it is easier to choose each part's green and to see what it sits on.

The Dark column is optional: the family shade each part takes on a dark screen.
family12345678910111213141516
meaning
Color roleThe partMeaningDark (optional)Sits on
Background
Border
Icon
Words
Background (filled)
Words (filled)
Part (inverted), optional
Additional (custom)

A row of sixteen empty boxes numbered 1 to 16, labeled family, then a meaning row with five names, subtlest, subtler, subtle, default, and strong, each with an empty field for a shade number, above a blank table with eight rows and five columns: the color role, the part, meaning, dark, marked optional, and sits on. Each cell in the Dark column holds a faded, empty field. Only the part column is filled in: background, border, icon, words, background (filled), and words (filled), then a faded row called part (inverted), optional, then a last row in italics called additional (custom).

Fill in the blanks. The family row takes the sixteen greens from article 3, with their codes. The part section has the standards of every system. You can change this to your custom work. In this example, the color role is success. The Meaning column is the loudness name from article 3's 5th step: subtler for the background, subtle for the border, default for the icon and the badge fill, strong for the words, subtlest for the badge words. No green number is written; the name stands for it. Sits on is what you checked contrast against in lesson 6: the background sits on the page; the border, icon, and words on the background; the badge fill on the page; the badge words on the fill. When a color changes, every row that sits on it gets checked again.

The inverted row is optional. Inverted, from article 1, is a part on a surface opposite to the screen, such as a dark toast in a light app. Fill this row only when a colored accent, such as a green check, sits on a dark patch: Icon (inverted), the meaning name of its green, and the dark patch under sits on.

green1#FAFFFB2#E6FEEA3#CDFED44#AFFEBF5#92FCAC6#6EF7997#52F4908#2CED839#11DF7B10#18BF7911#0D9C6A12#047B5D13#035E4C14#014B4015#07363016#022622
meaning
Color roleThe partMeaningDark (optional)Sits on
successBackgroundsubtlerthe page
successBordersubtlethe background
successIcondefaultthe background
successWordsstrongthe background
successBackground (filled)defaultthe page
successWords (filled)subtlestthe filled background
Part (inverted), optional
Additional (custom)

The same table filled in for success. Above it, the sixteen greens numbered 1 to 16, each box holding its number and its color code, then the meaning row: subtlest 1, subtler 3, subtle 5, default 12, strong 14, each with a swatch of its green. The Dark column is still faded and empty. The six standard rows each give a meaning name with a swatch of its green: subtler, subtle, default, strong, default, and subtlest. The last column says what each part sits on. The part (inverted) row stays faded and empty, and the additional (custom) row is left blank.

Step 2 · Write the list into Figma

In lesson 2 you chose one author: the one place where the colors get edited. Every other tool may read the colors, but only the author writes them. Here is that choice again, with the option this article uses marked.

Author
choose one
Design tool
Figma Variables, Tokens Studio, Penpot
Code editor
JSON written by hand or by an agent
Token platform
Supernova, Specify, Knapsack
Other tools may read; only this one writes.

The Author card from article 2: three options with a round button each, design tool, code editor, and token platform. The first, design tool, is selected, and Figma Variables is in bold among its examples.

The list from step 1 works with any of the three, because it records decisions, not a tool. In this article the author is Figma, a design tool, so step 2 shows how to write the list into Figma.

Figma keeps named colors as variables, and groups them in collections. Writing the list into Figma takes three collections, made in this order: the family first, the sixteen greens, so every green has a name; then the meaning, the five loudness names from article 3, each applied to its green; then the role, success, with one variable for each row of the list, each applied to its meaning. Each collection points at the one before it, so a change to one green in the family, or to one meaning, reaches every place that uses it.

1st - Create the family as a collection

Article 3 showed how to make the family. This is the one we will use here.

green12345678910111213141516

Shopify's sixteen greens in one row, numbered from 1, the lightest, to 16, the darkest. Values from Shopify's published token files.

Each of the sixteen becomes one variable in Figma, named by its number.

  1. Open the variables. Click Variables, the last icon in the rail on the far left of Figma.
  2. Make the family's collection. Click the plus next to "Collections". A new collection appears with its name, "Collection", already selected. Type "Green family" and press Return.
FileAgentsAssetsToolsVariables
Design system
Collections+
Collection
Groups
All0
Collection
No variables in this collectionSave colors, numbers, text, and states to reuse them in styles, prototypes, and across files. Learn more →
+ CreateImport

A drawing of Figma's Variables view just after the plus next to Collections is clicked. The plus is circled. A new collection called Collection sits in the list with its name selected in a blue box, ready to rename. The main area says there are no variables in this collection yet, with a blue Create button and an Import button.

  1. Add the sixteen greens. Click "Create", choose Color, name the variable green-1, and type its code from lesson 6 in the value cell. Repeat for green-2 to green-16.

You do this once per family. Success, and anything else that uses green, shares it.

FileAgentsAssetsToolsVariables
Design system
Collections+
Green family16
Groups
All16
Green family
NameValue
green-1FAFFFB
green-2E6FEEA
green-3CDFED4
green-4AFFEBF
green-592FCAC
green-6 to green-11
green-12047B5D
green-13035E4C
green-14014B40
green-15073630
green-16022622

The same view after the greens are added. Green family is the only collection, holding 16 variables. The main area is a table with a Name column and a Value column: green-1 to green-16, each with a small color icon before its name and a swatch and color code as its value. Rows 6 to 11 are folded to save space.

2nd - Create the meaning as a collection

The five loudness names from article 3's 5th step become a collection of their own, between the family and the role. Each name is applied to its green, so the role never has to touch a green directly.

  1. Make the meaning's collection. Click the plus next to "Collections" again, and type "Meaning" over the selected name.
  2. Add the five names. Click "Create", choose Color, and type the color role and the loudness name with a slash between them: success/subtlest. Press Return, and Figma makes a success folder with subtlest inside it. Repeat for success/subtler, success/subtle, success/default, and success/strong.
  3. Apply each to its green. Click the value cell, open the "Libraries" tab, and pick the green article 3 gave that name under Green family: green-1 for subtlest, green-3 for subtler, green-5 for subtle, green-12 for default, and green-14 for strong.
green1subtlestbadge words23subtlerbackground45subtleborder6789101112defaulticon, badge1314strongwords1516

The sixteen greens from the 1st part, with the five the role uses outlined. Under each outlined shade, its loudness name and the part it goes on: green 1 subtlest, the badge words; green 3 subtler, the background; green 5 subtle, the border; green 12 default, the icon and the badge; green 14 strong, the words.

FileAgentsAssetsToolsVariables
Design system
Collections+
Green family16
Meaning5
Groups
All5
success5
Meaning
NameValue
success
subtlestgreen-1
subtlergreen-3
subtlegreen-5
defaultgreen-12
stronggreen-14

The Variables panel with a second collection, Meaning, selected under Green family. Under a success group are five variables, subtlest, subtler, subtle, default, and strong, each showing the name of the green it is applied to: green-1, green-3, green-5, green-12, and green-14.

Five names for five greens, once per role.

3rd - Adding the role

  1. Make the role's collection. Click the plus next to "Collections" again, and type "Success" over the selected name.
FileAgentsAssetsToolsVariables
Design system
Collections+
Green family16
Meaning5
Collection
Groups
All0
Collection
No variables in this collectionSave colors, numbers, text, and states to reuse them in styles, prototypes, and across files. Learn more →
+ CreateImport

The Variables view as the role's collection is made. The plus next to Collections is circled. Green family and Meaning are already in the list, with 16 and 5 variables, and under them a new collection called Collection sits in a blue box with its name selected, ready to be renamed Success. The main area says there are no variables in this collection yet.

  1. Add one variable per row of the list. Click "Create", choose Color, and give it the token name for its part, built with the naming tree from article 1, written with slashes. Here is the tree again, starting on the background of success: static/bg/success/default. Article 1 explains each part of these names.
Try itClick any box to build a name. Each column is one part of the name. Pick one box per column and watch the name below change.
1 · kind2 · nature (2)3 · property (4)4 · intent (6)5 · variant
the name you built
The naming tree from article 1, five columns of boxes joined by lines: kind, nature, property, intent, and variant. The last column for static things has three boxes: default, inverted, and filled. The highlighted path reads color, static, background, success, default, and the name it builds is shown under the tree.

Type the name into the new row with its slashes, as one piece, and press Return.

FileAgentsAssetsToolsVariables
Design system
Collections+
Green family16
Meaning5
Success1
Groups
All1
Success
NameValue
static/border/success/defaultsuccess/subtle

A drawing of the Success collection with one new color variable. Its name box is open with a blue outline, and the name static/border/success/default is being typed into it. Its value shows success/subtle from Meaning, which step 3 applies. Under Groups, All is selected.

Figma turns each slash into a folder. One name makes three, one inside the other: static, border inside it, and success inside that. They appear under Groups, and the table shows the folder path as a heading, with only the last word, default, in the row. The next names fill in the same tree: static/bg/success/default adds a bg folder beside border, and static/bg/success/filled lands under the same heading as it.

FileAgentsAssetsToolsVariables
Design system
Collections+
Green family16
Meaning5
Success1
Groups
All1
static1
border1
success1
Success
NameValue
static / border / success
defaultsuccess/subtle

The same view after pressing Return. Under Groups, three new folders are shaded yellow, nested one inside the other: static, border, and success. The table shows a heading, static / border / success, with one row under it named default, holding success/subtle.

  1. Apply it to the meaning. Click the value cell, and instead of typing a code, open the "Libraries" tab and pick the name from the Meaning column under Meaning: success/subtle for the border. Do the same for every other row you filled in.
FileAgentsAssetsToolsVariables
Design system
Collections+
Green family16
Meaning5
Success6
Groups
All6
static6
bg2
success2
border1
success1
icon1
success1
content1
success1
label1
success1
Success
NameValue
static / bg / success
defaultsuccess/subtler
filledsuccess/default
static / border / success
defaultsuccess/subtle
static / icon / success
defaultsuccess/default
static / content / success
defaultsuccess/strong
static / label / success
filledsuccess/subtlest

The same view after the role is added. Three collections are listed, Green family with 16 variables, Meaning with 5, and Success with 6, and Success is selected. Under Groups, a nested list: All and static hold 6; under static come bg, border, icon, content, and label, each with a success group inside it. The table has a heading for each group: static / bg / success, with default and filled under it; static / border / success, static / icon / success, and static / content / success, each with default; and static / label / success, with filled. Each value is a gray chip with a swatch and a meaning name such as success/subtler, where the family's table showed color codes.

The chip is the point of the 3rd part. A value picked from Meaning shows the meaning's name, not a green and not a code, so the Success collection says exactly what the list says. Click the chip and Figma shows the meaning; click that, and it shows the green. If success ever has to change, the five lines in Meaning change and every place follows.

  1. If you filled the Dark column. Add a mode called Dark to the Success collection, a second column of values, and in it apply each row to the family shade from its Dark cell. On Figma's free Starter plan a collection has one mode, so make a second collection called Success Dark with the same names instead.

With AI

Three ways to work with AI here, using different methods and tools.

  1. An agent connected to Figma. In this method, you can connect any AI tool that has an MCP, Model Context Protocol, connection to Figma. Claude Code, for example, reads the file's layers and variables and can write variables back.
  2. AI writes a token file, a plugin imports it. You give any chat AI the list and ask for a token file in the design tokens standard format. A Figma plugin such as Tokens Studio or Variables Import reads that file and makes the collections. It works on any Figma plan and needs no agent connection. In other author tools, the same file goes in through the tool's own import, such as Penpot, which reads it without a plugin.
  3. A capture, outside Figma. You screenshot the drawing and paste it into any chat AI, such as Claude or ChatGPT, with the prompt. It can write the rows, but from a picture only. Color codes come out as guesses you would have to check. To make it accurate, type the hex code next to the item with its part, like #92FCAC border.

Start with the list

You fill out the list by hand↓The agent makes the collections

For a designer who filled out the list by hand. Steps 1 and 2 below.

Start with the drawing

You draw the component and name its layers↓The agent reads the layers and writes the list↓The agent makes the collections

For a designer who drew the component in lesson 6 and named its layers. The agent reads the layers and writes the list for you. Not covered here.

Two columns of boxes joined by arrows. Left, starting with the list: you fill out the list, the agent makes the collections. Right, starting with the drawing: you draw and name the layers, the agent writes the list, the agent makes the collections. Boxes for what the agent does are shaded purple.

This article will focus on 1, connecting an MCP to Figma.

Step 1 · Fill out the list

Same list from Step 1 by hand, filled out on the color role worksheet. Copy it as text or download the PDF for step 2.

Step 2 · Write the list into Figma

The same three parts, 1st the family, 2nd the meaning, and 3rd the role, in one request, with the sheet from step 1:

Here is my color role sheet: [paste the text, or attach the PDF]. For each color role in it, make three things. First, a collection named after its family, with one color variable per shade in the family row, numbered as the sheet does, holding the codes. Second, in one collection called Meaning, a group named after the role, with one color variable per name in the role's meaning row, each applied to that family's shade by the number the sheet gives. Third, a collection named after the role, with one color variable per row of its list, named with the token name for its part, such as static/bg/success/default, each applied to the Meaning variable in its row. If a row has a shade in its Dark column, add a mode called Dark to the role's collection and, in it, apply that row's variable to that family shade; if the plan allows one mode only, make a second collection named after the role with Dark added, holding the same names.
FileAgentsAssetsToolsVariables
Design system
Collections+
Green family16
Meaning5
Success6
Groups
All6
static6
bg2
success2
border1
success1
icon1
success1
content1
success1
label1
success1
Success
NameValue
static / bg / success
defaultsuccess/subtler
filledsuccess/default
static / border / success
defaultsuccess/subtle
static / icon / success
defaultsuccess/default
static / content / success
defaultsuccess/strong
static / label / success
filledsuccess/subtlest

The Variables panel after the agent's request: Green family with 16 variables, Meaning with 5, and Success with 6, with Success selected and the same groups and rows as the by-hand version above.

Check the panel against the by-hand pictures above. What you no longer do is type the variables.

The list is the record, and the three collections carry it into Figma. Lesson 8 lets a program turn the names into the files screens are built from, and lesson 9 writes the rules for using the names where people and tools can both read them.

Repeat the two steps for the other color roles, if not done so yet.

Lesson 8 · Let a tool write the files

The handoff

Lesson 2 decided where the colors are kept: one place people edit, and copies made from it. Here is that choice again, with the option this article uses marked.

Store
choose one
The design file itself
Figma as the record. No history of changes, no review.
Git repository
JSON, versioned, reviewed. The default.
Platform database
Supernova or Specify hold it.
The one place you would fix a mistake first. Everything after this is a copy.

The Store card from article 2: three options with a round button each, the design file itself, Git repository, and platform database. The second, Git repository, is selected.

This is where the handoff occurs. The three collections in Figma are a working system for a design team, and they are all a developer needs. Two ways to hand them over:

  1. Share the Figma file. Click Share at the top right of Figma, add the developer's email or copy the link, with "can view". They, or an agent connected to the file, read the three collections from there.
  2. Or export the token file. Ask the agent that made the collections:
    Write every color collection in this file, each family, the Meaning collection, and each color role, as one token file in the design tokens standard format, named tokens.json. Keep the names as they are, with each variable pointing at the variable it is applied to. Where a collection has a Dark mode, include its values.
    Or, in a plugin such as Tokens Studio, choose Export. Send the file.
TipIf you chose the second way in the With AI list, the token file the AI wrote is already this file, and it is all the developer needs.

The designer's role stops at the handoff. What follows is usually a developer's job. For the sake of this blog, we'll continue into how it gets set up in a repository: a shared folder of files kept by a version control tool such as Git, where every change is recorded with who made it and when, and can be reviewed before it lands. In a company it is standard practice, for three reasons.

  1. The website is developed from files, not from Figma, so the colors have to reach the code as files.
  2. A repository keeps the history, so a wrong green can be traced to the change that made it and put back.
  3. A change is reviewed before it lands, so a token file is not edited by accident the way a value in a design file can be.

Developer zone

From here on this is the developer's work. This is where the actual colors are pulled from to develop the product: the website, or the app. If you are the designer, read on to know what happens to your file.

A developer who has worked with tokens will set up the program below. On a team that has not, ask about this part, otherwise it might sit in the repository while the codes keep being copied by hand. After that, each new file is the whole handoff.

Three tiers, one file

The one place is the token file from the handoff: one small JSON file, plain text with names, values, and braces, in three parts, one per tier. It is written in the format the design tokens standard describes, so that other tools can read it too. It goes in the repository as it is. Here is the background of the "Saved" message in all three parts.

tokens.json · tier 1 · shades
"green": {
  "3": { "$type": "color", "$value": "#CDFED4" },
  "15": { "$type": "color", "$value": "#073630" }
}
The only part with color codes in it.
tokens.json · tier 2 · meaning
"success": {
  "subtler": { "$type": "color", "$value": "{color.green.3}" },
  "subtle":  { "$type": "color", "$value": "{color.green.5}" }
}
Every value is a pointer at tier 1, written in braces.
tokens.json · tier 3 · places
"static": { "bg": { "success": {
  "default": { "$type": "color",
    "$value": "{color.success.subtler}",
    "$extensions": { "mode": { "dark": "{color.green.15}" } }
  }
} } }
The value points at tier 2. The dark shade, from the Dark column, points at tier 1.

Three parts of one file side by side. The first holds two greens with their color codes. The second holds two meaning names, each pointing at a green in braces. The third holds one place name whose value points at a meaning name, with a dark shade under it pointing at a green.

And the whole file for the success role, with the family cut to the greens the role uses.

// tokens.json { "color": { "green": { "1": { "$type": "color", "$value": "#FAFFFB" }, "3": { "$type": "color", "$value": "#CDFED4" }, "5": { "$type": "color", "$value": "#92FCAC" }, "6": { "$type": "color", "$value": "#6EF799" }, "8": { "$type": "color", "$value": "#2CED83" }, "12": { "$type": "color", "$value": "#047B5D" }, "13": { "$type": "color", "$value": "#035E4C" }, "14": { "$type": "color", "$value": "#014B40" }, "15": { "$type": "color", "$value": "#073630" } }, "success": { "subtlest": { "$type": "color", "$value": "{color.green.1}" }, "subtler": { "$type": "color", "$value": "{color.green.3}" }, "subtle": { "$type": "color", "$value": "{color.green.5}" }, "default": { "$type": "color", "$value": "{color.green.12}" }, "strong": { "$type": "color", "$value": "{color.green.14}" } }, "static": { "bg": { "success": { "default": { "$type": "color", "$value": "{color.success.subtler}", "$extensions": { "mode": { "dark": "{color.green.15}" } } }, "filled": { "$type": "color", "$value": "{color.success.default}" } } }, "border": { "success": { "default": { "$type": "color", "$value": "{color.success.subtle}", "$extensions": { "mode": { "dark": "{color.green.13}" } } } } }, "icon": { "success": { "default": { "$type": "color", "$value": "{color.success.default}", "$extensions": { "mode": { "dark": "{color.green.8}" } } } } }, "content": { "success": { "default": { "$type": "color", "$value": "{color.success.strong}", "$extensions": { "mode": { "dark": "{color.green.6}" } } } } }, "label": { "success": { "filled": { "$type": "color", "$value": "{color.success.subtlest}" } } } } } }

One JSON file in a dark code box. Under color, three groups: green, with nine shades and their codes; success, with five meaning names each pointing at a green in braces; and static, with the six place names nested by part, each pointing at a meaning name. The background, border, icon, and words each carry a dark entry under their value, pointing at green 15, 13, 8, and 6.

Into the repository

The developer puts the JSON in the project, in a folder usually called tokens, and records it with three commands: add the file, commit it with a message that says what changed, and push it to the shared copy.

# in the project's folder git add tokens/tokens.json git commit -m "Color roles: success, first version" git push

Three commands in a terminal: git add with the file's path, git commit with a message in quotes, and git push.

Then a pull request: a page where another developer sees the change, line by line, and approves it before it lands. Every later change to the file takes the same path, add, commit, push, review, so the history and the review from the three reasons above come for free.

From Store to Consume

The website consumes a style file, not the JSON. Lesson 2's last card, Consume, listed what gets made from the store. This article makes two of them: the Web CSS here, and the docs in lesson 9.

Consume
as many desired
for output
Figma
variables synced back from the store
Docs
design-system.md, Storybook
Web CSS
variables.css, Tailwind theme
iOS · Android
Swift and Kotlin constants
All made by a tool from the store.

The Consume card from article 2: four options with a square check box each, Figma, docs, web CSS, and iOS and Android. Docs and Web CSS are checked.

The program, in this case we will use the example of Style Dictionary, a free tool made for exactly this, is short. It reads the file, follows every pointer until it reaches a color code, and writes the style file: one block of lines for light screens and one for dark. The output goes in a folder nobody edits. If a pointer points at a name that does not exist, the program stops and says which one. That is the cheapest check in the whole system, and it catches the typo that a hand-typed file would carry for months.

Three steps get from the repository to a .css file.

  1. Install it. In the project's folder, one command: npm install style-dictionary. It is now a tool the project carries, like any other.
  2. Tell it what to do. A config file next to the tokens, a few lines: where the token file is, and what to write out, here a CSS file.
// config.json { "source": ["tokens/tokens.json"], "platforms": { "css": { "transformGroup": "css", "buildPath": "build/css/", "files": [{ "destination": "variables.css", "format": "css/variables" }] } } }

A config file in a dark code box: a source line pointing at tokens/tokens.json, and a css platform that writes variables.css into a build folder.

  1. Run it. npx style-dictionary build. It reads tokens.json, follows the pointers, and writes build/css/variables.css. The dark block comes from the dark entries, written as a second pass with a few more lines of config, and the agent writes those. The website links variables.css like any other style file. Run it again whenever tokens.json changes, by hand or as part of the site's build. Or ask the agent in the project to do all three.

Here is what it writes for the success role.

/* written by the program, never by hand */ :root { --color-static-bg-success-default: #CDFED4; --color-static-border-success-default: #92FCAC; --color-static-icon-success-default: #047B5D; --color-static-content-success-default: #014B40; --color-static-bg-success-filled: #047B5D; --color-static-label-success-filled: #FAFFFB; } [data-mode="dark"] { --color-static-bg-success-default: #073630; --color-static-border-success-default: #035E4C; --color-static-icon-success-default: #2CED83; --color-static-content-success-default: #6EF799; --color-static-bg-success-filled: #047B5D; --color-static-label-success-filled: #FAFFFB; }

A style file excerpt in two blocks. The first block, for light screens, lists the six success place names with their color codes. The second block, for dark screens, lists the same six names with different codes, except the badge fill and its words, which stay the same in both.

Now change the green in one place. Edit the code next to green 3 in tokens.json, run the program, and every screen that uses the background of a success message is rewritten. Nobody searches the website for the old code. Nobody misses one. The row in lesson 7 was a decision; this is what makes the decision stick.

Lesson 9 · Write the rules down

The names exist and the files exist. To help everyone use them the same way, one page says when to use each name, and when not to. The list recorded where each color goes. Lesson 9 writes the rules for reaching for it: which name for which job, what is forbidden, and what to do when the name you need is not there.

Without this page, the next person to build a screen, a developer, another designer, or an agent, types a color code, such as #047B5D, instead of the name.

The page has two types of users. A person skims it before building a screen. A tool reads it before writing one. It is saved in the repository as design-system.md, next to tokens.json, so people and tools both find it. Here is the one for this series' color roles.

Quick reference · color

Never a color code in a screen. Use a place name:

--color-{static|action}-{bg|border|icon|label|content}-{role}-{version}

  • static is for things you look at: messages, badges, cards. Its version is default, or filled for a small shape filled solid, such as a badge, and the words on it, or inverted for a part on the opposite background.
  • action is for things you press: buttons and links. Its version is default, hover, or pressed.
  • bg is the fill, border the edge, icon the mark, label short words on the interface, content the words people read.
  • Roles: success an action finished or a status that is good · warning needs attention, does not block · critical impossible, blocked, or an error · info worth noticing · neutral carries no meaning.

Light and dark live inside the name. Do not write a second color for dark screens. If a color is unreadable in one mode, the fix is the dark entry in the token file, not the screen.

The old names are gone. There is no green, no #047B5D, and no ok in a screen. Those were the names before the system. Do not bring them back.

Missing a name? Add it to the token file, run the program, then use it. Never type a value "for now".

A one-page quick reference. A rule in bold, the name pattern with its five slots, four lines explaining the slots and the roles, and three more rules: light and dark live in the name, the old names are gone, and what to do when a name is missing.

What you can do now

Take each row of your Lesson 7 table and write it three times: the shade by family and number, the meaning it carries, and the place it is used, with the five-part name from article 1 and, if your screens go dark, its dark shade. Keep the three tiers in one small file, and let a program follow the pointers and write the style file, so that changing a shade in one place changes every screen that uses it. Then write one page of rules: the name pattern, the roles in a line each, what is forbidden, and what to do when a name is missing. And answer the question that starts article 5: now that the names exist, how do you make sure every screen, old and new, actually uses them?

Next · Stage 5 · Implementing consistency of the design system: a checker that holds back a hand-typed color, the existing screens changed over to the names, and a human check before release.

The design system series

  1. 1Introduction to design tokens13 min
  2. 2Choosing the color roles19 min
  3. 3Expanding on color roles19 min
  4. 4Writing the colors into a design system You are here30 min
  5. 5Implementing consistency of the design system19 min
  6. 6Take it into FigmaComing soon

Share this post

Written by Suzanne Sallaj

Product designer working on agentic AI, six years across healthcare, fintech and consumer.