Suzanne Sallaj

Design systems · Stage 5 of 6 · Implementing consistency of the design system

Implementing consistency of the design system

By Suzanne Sallaj

· 19 min read · design system series, part 5

Three lessons on a checker, the changeover, and the human check before release.

You are here

In this article, we will cover the following:

  1. Build a checker
  2. Change the existing screens over
  3. Human check before release

These are lessons 10, 11, and 12 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 8 and 9 were the fourth, Writing the colors into a design system. 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 10 to 12 shown
Lessons 8 and 9Covered in the fourth articleLet a tool write the files · Write the rules down
10
Build a checkerchecking

A tool that stops anyone from typing a color by hand when a name exists for it.

ExampleSomeone types the code for the strong green. The checker catches it and says: use "success".
Lesson 10
11
Change the existing screens overreplacing

Go through the screens that already exist and replace every hand-typed color with its name.

ExampleA screen that has the code for the strong green in forty places now says "success" in forty places.
Lesson 11
12
Human check before releaselooking

Open each screen, in light and in dark, and check with your own eyes that it looks right.

ExampleA success message that reads well on a light screen may be hard to read on a dark one. You only find out by looking.
Lesson 12

You spent four articles building a system. Three months later you open the live product and the success green is wrong on one screen, a badge is a green you never chose, and the dark mode you specified is someone's guess. The design file says one thing and the product says another. Every review becomes a hunt for colors nobody remembers typing, and the design system exists only as a thought.

This article is how the system stays true after you hand it over: find, fix, look. A checker holds back any color that is not in the design system. You build it once, with an AI agent or a developer, and from then on the checker does the checking. This is about building an automated system that keeps the design system consistent without ongoing work. You still make the design decisions.

Lesson 10 · Build a checker

Step 1 · Writing the rules for the checker

By hand

Level 1 · simple

Flag

  1. Any color typed as a code, like #047B5D.
  2. Any color name that is not in the token file.

Leave alone

  • transparent, which means no color.

Level 2 · expanded

Flag

  1. A color typed as a code: #047B5D, rgb(4, 123, 93).
  2. A color from a built-in palette: text-green-600.
  3. An old name from before the system: brand-green.
  4. A second color written only for dark screens: dark:text-green-400.
  5. A name shaped like a token that is not in the file: --color-static-content-primary.

Leave alone

  • transparent, currentColor, and inherit, which are not color choices.
  • Code from a library you do not own.
  • Test files.

Decide

  • Plain white and black: allowed, or names of their own?
  • A lighter color made with transparency, such as bg-success/10: allowed, or a new name in the family?

Two panels side by side, level 1 and level 2, each headed with a small three-bar icon, one bar green for level 1 and two for level 2, and each holding a list to write. Level 1 flags two things and leaves transparent alone. Level 2 flags five things, leaves three alone, and lists two decisions.

With AI

To be able to use AI
As a designer, you'll need access to the app's repository in order for the agent to analyze it. Choose one:
  • GitHub Copilot, which connects to the repository through your GitHub account.
  • A copy on your computer. With a GitHub account that has permission to the repository, download a copy and open it with an AI coding tool such as Claude Code or Gemini CLI.
  • Claude Code in the browser, at claude.ai/code, connected straight to GitHub.
  • No access? Hand your list to a developer, who runs the prompt and sends you the reply.

Article 4 ended with two files handed off to developers: tokens.json, the token file, and design-system.md, the rules page. Make sure to connect them to the AI agent, along with the in-review repository for this step.

Level 1 · simple

Read tokens.json. I want a checker that flags any color typed as a code, and any color name that is not in tokens.json. Leave transparent alone. Do not build it yet. Tell me what it would flag in this app, with three examples.

It would flag 214 places. Three examples:

  • #047B5D in OrderBadge.css, line 12. Use --color-static-bg-success-filled.
  • brand-green in Header.css, line 4. That name is not in tokens.json.
  • #FFFFFF in Card.css, line 9. There is no name for white in tokens.json yet. Add one, or tell me to allow it.

Level 2 · expanded

Read design-system.md and tokens.json. The screens in this app still use typed color codes, built-in palette colors, and the old names from before the system. Before we change anything, I want a checker that finds every place a screen uses a color that is not a name from the token file. Do not build it yet. Tell me what you would flag and what you would leave alone.

I read both files and scanned the app's code. Nothing has been changed.

I would flag:

  • Typed color codes, about 210, such as #047B5D in OrderBadge.css.
  • Built-in palette colors, about 150, such as text-green-600.
  • Old names, about 340. muted-foreground alone is 120 of them.
  • Second colors for dark screens, about 45.
  • Names not in the token file, 3, such as --color-static-content-primary in LoginGate.tsx, which paints nothing.

I would leave alone: transparent, currentColor, and inherit; the library folder; test files.

I need your decision on: plain white, used 38 times; bg-success/10, used 12 times; and an orange with no role, used 5 times.

Two panels side by side, level 1 and level 2, each with a prompt and, under it in purple, an example of what the agent writes back. Level 1's reply gives a count and three examples, the last one a question about white. Level 2's reply lists what it would flag with a count for each, what it would leave alone, and three decisions it needs from you.

Step 2 · Building the checker

What it is

The checker is a set of rules added to the checking tool most apps already run to catch mistakes in their code. Your list from step 1 becomes those rules.

What it does

Every time someone saves or pushes code, the checker reads the app's code and stops at any color on your list. It names the file, the line, what is wrong, and what to use instead. A typed code that matches one name is corrected on its own. Anything else is held back until a person decides, so the color never reaches the product.

Normally, this is where a developer steps in. If they have the bandwidth, follow the steps for the handoff. Otherwise, continue here.


Option AIn the designer's hands

When a designer would do this

With an AI agent, a designer can now help build the checker. Why would a designer want to?

  1. The team's backlog is already full. A checker is not a feature, so it can wait behind feature work for months while the colors keep drifting. Building it with an agent gets it in without taking a developer off that work.
  2. The team is small. There is no one whose job is the design system. If you do not build it, nobody does.
  3. You take the design system further. Your rules stop being a page people are asked to follow and become part of how the product is built. They are your design decisions, so they go in right the first time.

A developer still reviews and puts it into the app.

The steps for a designer, with AI

  1. Open the repository with your agent. Any of the ways in step 1's note.
  2. Give it the build prompt.
    Build the checker from my list and save it as one new file, stylelint.config.js. Do not install anything and do not change any existing file. When a typed color code matches exactly one name in the token file for that part, the checker should correct it automatically once it is turned on. When more than one name could fit, or none does, it should flag it and suggest the closest name. Then run it once on the whole app and tell me what it finds, in plain words.

    This turns your list into a checker and shows you what it would find, without changing anything in the app. Once a developer turns it on, it runs on its own every time someone saves a change. It will automatically correct a typed color code to match the naming convention in the design system. It offers the best guess, and a person decides, when the code does not match a color in the design system or more than one name could fit. Only a color that is not using a name from the design system is held back from the product.

    Other prompt ideas:

    • Warnings first. The checker reports every flagged color but does not stop the build yet. Useful when the first run finds hundreds and the team needs time to fix them.
    • New code only. It checks only the files people change from now on, so old screens do not block anyone until lesson 11 changes them over.
    • One kind of file first. It checks style files only, and component files are added later.
  3. Read what it reports. The agent names the file it saved, then tells you what the checker found. It reads something like this:

    I built the checker. Nothing in the app has changed, and nothing was installed.

    New file

    • stylelint.config.js, your rules: no color typed as a code, and no name that is not in tokens.json. It also holds the part that finds the closest name for a typed code.

    What it found: 214 colors in 38 files

    • 96 match exactly one name. Once the checker is turned on, these are corrected automatically. Example: #047B5D in OrderBadge.css, line 12, becomes --color-static-bg-success-filled.
    • 87 could be more than one name. Example: #E8F5EE in Toast.css, line 6, could be --color-static-bg-success-default or --color-static-bg-brand-subtle.
    • 28 are not a color in the design system. Example: #FF5A36 in PromoBanner.css, line 3. Closest: --color-static-bg-danger-filled, but it is noticeably different.
    • 3 use a name that is not in tokens.json. Example: brand-green in Header.css, line 4.

    To turn it on, a developer connects it to the app's build.

    Look at the most common matches in each group. If something flagged is not a color at all, tell the agent not to flag it.

    When a color is on purpose
    The checker flags every color that is not using a name, including a small creative pop. Decide which kind it is and tell the developer:
    1. A new addition to the system. Decide the role, add it in Figma, update tokens.json and the rules page, then send it to a developer.
    2. It is a one-time choice. "This color is on purpose here. Mark it so the checker lets it through." The developer adds a short note on that line, and a reviewer can see it was a choice, not drift.
  4. Check the checker. This tests the checker, not the app. Before you trust the count, make sure it catches what it should and nothing else.

    Example:

    • A name from your token file: --color-static-bg-success-filled
    • A hex code: #047B5D
    Test the checker before I trust the count. Write two short lines. One uses [insert a name from your token file] and should pass. The other has [insert a hex code] typed in and should be flagged. Show me both lines and what the checker says about each.

    It should come back with something like this:

    I wrote two test lines with the name and the hex code you gave me, in a scratch file outside the app, and ran the checker on them.

    Line 1: background: var(--color-static-bg-success-filled);
    Passed, no problems.

    Line 2: background: #047B5D;
    1 problem: #047B5D is a color typed as a code. It matches one name, so it will be corrected to --color-static-bg-success-filled.

    The checker works as expected.

    Try it: type a line, or pick an example

    The names this example checks against

      An interactive box. Pick an example or type style code, and the checker below it answers for each line: passed, corrected to a name, did you mean a name, or flagged with the closest name. It checks against the six success names from article 4's token file, listed under the box.

      If it flags the first line, it is too strict. If it misses the code on the second, it is too loose. Either way, ask the agent to fix it and test again.

    • Send the saved file (stylelint.config.js) to the developer. Ask the developer to review it for acceptance. Once it is accepted, the checker runs on its own every time someone saves a change. Add one line to design-system.md: after any change to a screen, run the checker; a typed color is a bug to fix.

    Option BIn the developer's hands

    When to hand the rulebook to a developer

    • You do not have access to the repository.
    • The app is large, or writes colors in more than one kind of file.
    • The build and release setup is something only developers touch.
    • A developer has the time. Then it is quicker for them.

    Hand them your list from step 1. It is the whole brief.

    What to expect from the developer

    1. They turn your rulebook into rules the checker can read.
    2. They connect it to the app's build and turn it on.
    3. They send you what the first run found, so you can read it.

    The first run is a measurement Example

    The first run tells you how big the clean-up is before you start, with an end goal of zero.

    match exactly one name96
    could be more than one name87
    not a color in the design system28
    a name not in tokens.json3
    total, 38 files214

    Four horizontal bars in red, one per kind of flagged color, longest first: 96 match exactly one name, 87 could be more than one name, 28 are not a color in the design system, 3 are a name not in tokens.json. A total line reads 214 across 38 files.

    The first run found:

    • 214 colors in 38 files that do not use a name from the token file.
    • 96 are corrected on their own once the checker is turned on.
    • 118 wait for a person. Many are the same color used in several places, so they come to about 40 decisions, made in lesson 11.

    Lesson 11 · Change the existing screens over

    The remediation: Essentially, it is a run of the build to fix per your rules. What happens after the run is every value with a clear rule is changed to its name, and the forty or so that need a decision are listed for you to decide and sign off.

    Ask the developer to run it, or give your agent one prompt:

    Change every screen over to the names in tokens.json until the checker finds nothing. Fix everything that follows a clear rule. Do not decide anything that needs a judgment call; list those in reports/changeover-decisions.md for me.
    214typed colors · 38 files · before
    →
    0after · the build passes · the checker is green

    Two large numbers with an arrow between them: 214 in red, labeled typed colors across 38 files before, and 0 in green, labeled after, the build passes.

    Three kinds of change

    Every one of the 214 fixes was one of these.

    Renamesame thing, new nameThe old export called muted words text-muted-foreground. Now it is the place name for muted content. Nothing on screen changes; the name says what it is for.
    Replacea code becomes a nameA typed #047B5D on an icon becomes --color-static-icon-success-default. The screen may shift a little, because the name's green is the one the family chose, not the one someone typed from memory.
    Deletelines that no longer need to existEvery line that set a second color for dark screens: gone, because the name already holds its dark value.

    Three cards side by side: Rename, same thing new name; Replace, a code becomes a name; Delete, lines that no longer need to exist. Each has two sentences explaining it.

    The same badge, before and after Example

    before · six underlines
    background: #DCFCE7;
    color: #15803D;
    border: 1px solid #BBF7D0;
    @media (prefers-color-scheme: dark) {
      background: #14532D;
      color: #4ADE80;
      border-color: #14532D;
    }
    after · clean
    background: var(--color-static-bg-success-filled);
    color: var(--color-static-label-success-filled);
    border: 1px solid var(--color-static-border-success-default);

    Two code boxes side by side. On the left, a badge's style with six color codes, each underlined in red, three of them inside a dark mode block. On the right, the same badge with three place names in green and no dark mode block.

    Auditing the changes flagged Example

    The run writes every judgment call to a decisions file for you to review. Ask the developer to send you anything from the results that needs a design review.

    This is where you can make decisions and add to the rules page, design-system.md, mentioned in step 1.

    reports/changeover-decisions.md

    foundchanged towhy
    #22A06B, the line on the trends chart, TrendChart.tsx--color-static-icon-success-defaultTwo greens could fit. The line shows things going well, so it takes success.
    #F79009, an orange used in 5 places, such as PromoBanner.cssNot changed. Waiting for you.No role fits. Is it a new warning role, or five one-off choices?
    bg-success/10, a see-through green behind toasts, Toast.css--color-static-bg-success-defaultClosest solid color. It reads slightly stronger than before.
    A border 3 pixels wide on cards, Card.css2 pixelsThe nearest border width in the system.
    A sidebar 268 pixels wide, Sidebar.tsx256 pixelsThe nearest width step. Check the sidebar labels still fit.
    and 35 more

    A table headed with the file name reports/changeover-decisions.md, with three columns, found, changed to, and why, and five example rows: a chart green mapped to the success name, an orange left waiting for the designer, a see-through green mapped to the closest solid name, a three-pixel border changed to two, and a sidebar width changed to the nearest step. A last row reads "and 35 more".

    Lesson 12 · Human check before release

    The final check. By now you have written the rules, built the checker, tested it, run it on the app, made the decisions it could not, and changed every screen over to the names.

    One step is left: look at the app with your own eyes.

    The checker reads the code. It cannot see what a screen actually shows, and between the code and the screen, other programs can still change a color. Ask the developer for a preview link, a private copy of the app with the changes in it, or review if live.

    What looking could find Example

    The checker said zero. The first screenshot showed a bug that no check for typed codes could see.

    before the fix
    Log in to see this page
    Sign in to see your saved connections and insights.
    Log in
    ↑ white words, no fill: the button is there, you cannot see it
    after
    Log in to see this page
    Sign in to see your saved connections and insights.
    Log in

    Two drawings of the same login screen, a lock icon, a title, a line of text, and a button. On the left the button has white words and no fill, so it is invisible, with a red note pointing at the empty space. On the right the button has a blue fill and white words.

    The button's name was --color-static-content-primary. It looks like a token. It has the right shape and the right words. It is not one: there is no primary under static content in the token file. The browser found nothing by that name and painted nothing. The first version of the checker passed it, because it only looked for typed codes. This screen is why the second flag in lesson 10's level 1 list, a name that is not in the token file, exists.

    If you find errors

    1. Decide where the problem came from.
      • The code. The screen uses the wrong name, or a color is missing. Send it to the developer to fix, with a screenshot.
      • The design. The screen uses the right name, but the color itself is wrong, such as a green too light in dark mode. That one is yours: change the color in Figma and update tokens.json, as in article 4. Every screen that uses the name changes with it.
    2. If the checker should have caught it, add it to your list from step 1 and ask the developer to add it to the checker. That way the same mistake is flagged on its own next time.

    Congratulations. A design system is now in place 👏

    What you can do now

    Find, fix, look. Write the list of what the checker flags, build it with an agent or hand it to a developer, and test it before you trust the count. Let the run fix every color with a clear rule, and decide the rest yourself. The code is the developer's; the decisions are yours.

    Next · Stage 6 · Take it into Figma: the token file synced back into the design file, so the design and the code read from the same place, and the components built on the names.

    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 system30 min
    5. 5Implementing consistency of the design system You are here19 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.