Case study · Design system

A design system engineers used

When I joined, there was no design system. I built one, got the naming wrong for the people who mattered most, and fixed it. Then the system had to carry four products.

My role: Product Designer, built the system in Figma and co-governed it with the frontend lead Team: 2 designers, Frontend lead, Engineering

  • ~8 → ~3repeat questions from developers, per day
  • 4 productsrunning on one set of components
  • 1 designfor light and dark mode, not two

The starting point

No design system, just a library and some styles

The frontend used the Ant Design library. The Figma file had a set of colour styles and a handful of components, with nothing tying them together.

Light and dark mode were two separate sets of colour styles, so every screen had to be designed twice: once for light, again for dark.

Decision 1

Turn the colours into tokens

I turned the colours into tokens and built light and dark mode on top of them. One design, two modes, from the same set of tokens.

The first version had two layers. 88 primitives held the raw palettes: one set, with no modes. On top of them, 28 role tokens gave each colour a job, with a light and a dark value each. Designers only used the role tokens.

Trade-off: 88 primitives for a single product. Designers never saw them, but they were a lot to maintain.

Version 1: one set of palettes; each role token picks one step for light mode and one for dark
Decision 2

Name the tokens by what they're for

I gave the tokens descriptive names, written for designers: my teammate and I knew exactly where each colour belonged, and our designs came out consistent in design review.

The cost

The names made sense in Figma, not in the code

Our developers work from Figma, and they had already built themes in the code with their own names. Every handoff turned into a translation:

Name in Figma
Color-Base-Solid-bg
≠
Name in the code
cardColor

“Which colour is this in our code?”

Developers were asking design questions like that about 8 times a day.

Decision 3

Rename the tokens to match the code

I went back and gave the tokens the same names as the code: background and surface where the code named roles, cardColor and sideBar where it named components. For us, a smooth handoff to development was worth more than names that read nicely to designers. That set the number too: 28 role tokens, one for each name the code already used.

Trade-off: a mixed naming scheme, part role and part component. Less pure, but one name across Figma and code, written down as a deliberate choice.

Building on it

Ant Design first, custom only on purpose

We kept Ant Design's defaults wherever they worked, and documented our own components where the product needed more, each with every variant and state. With the frontend lead I set up one path for anything new, and design reviews with engineering before each release to catch mismatches before users see them.

Scale

From one product to four

The system grew to carry four products, each with its own identity. Version 1 mixed two questions in the same tokens: which product is this, and which theme is on? So I split them into separate layers:

  1. Source. 270 raw colours, in one place. No modes.
  2. Identity. One mode per product. Brand, primary, neutral and status colours (success, error, info, warning).
  3. Semantic. Light and dark mode. Each role picks the right step from the product's identity.

A product picks its identity; a theme picks the step. Each decision is made once, in its own layer, and the components never change.

Version 2: a product picks its identity, a theme picks the step, and four products share one set of components
Decision 4

Brand isn't always the action colour

For most products, primary is the brand colour. One product's brand is a bright yellow: as the action colour, it dominated every screen. So that product's primary is black, and yellow became its accent. The components didn't change; only that product's identity values did.

Trade-off: brand and primary are separate tokens in every product, even where they hold the same value.

The Button: every type, state and size, set through its properties
The same Button across four products, in light and dark: only the mode changes
What changed from v1

The product got its own layer

Version 1 already put light and dark mode on the role tokens, but each role pointed straight at one product's palette. In version 2, the semantic tokens point to the identity layer instead. The same semantic tokens, and the same light and dark steps, now serve all four products.

Now

Fewer questions, and better ones

Repeat questions from developers dropped from about 8 a day to about 3, observed by the team rather than measured with a tool. The questions that remain are different too: “does this new case need a system decision?”

What I learned

A design system has two audiences. Check how the code is built before naming anything. And keep each decision in one layer: the product in identity, the theme in semantics.

What I'd do differentlyI'd split product and theme from the start. Version 1 pointed the role tokens straight at one product's palette, and that had to be rebuilt when the second product arrived.

Next case →
Answers before the ticket
End of case study

Corporate banking · Design system · Live