Home > Product Work > A design system sized to its product

DESIGN SYSTEM · DESIGN TOKENS · FIGMA ↔ CODE

A design system sized to its product

Only what the product uses, and the reasons for not building more · Design Technologist, solo · 2026

After co-leading a design system for eight brands at Dow Jones, I built one for a single product, StayKeel. The rules are the same. The question was how many of them one product actually needs.

Design SystemDesign TokensAtomic DesignComponent LibraryCSS Custom PropertiesFigma VariablesThemingAccessibility

The source is the theme

In a multi-brand system, one theme keeps every product on the same structure: same token names, different values. Here there is one product, but five kinds of content, and each needs its own colour on the card. So I treated the five sources as five themes. The colour is the theme, and the theme is where the token architecture starts.

Three levels. Raw values that no component ever reads. A scope per source that remaps six contextual tokens. And the contextual tokens, which are the only thing a component reads. The card does not know YouTube exists. Adding a source tomorrow is one block of CSS and zero lines in any component.

The Challenge

Keep the discipline of a system built for sixty designers, without its weight. Decide what deserves a token, what deserves a component, and what should stay a one-off, when there is nobody to ask and no second product to justify an abstraction.

My Role

Architecture, tokens, components, documentation

  • Designed the three-level token architecture and its naming.
  • Built it in CSS custom properties, with a generated token page and a drift check.
  • Decided which parts become components and which states exist.
  • Mirrored the system in Figma from the product, not before it.

Scope

  • 113 tokens, each with a documented role
  • Five content sources as theme scopes, plus a fallback
  • 38 components and 162 variants in Figma, every one shipped and labelled IN CODE; nothing designed that is not in production
  • Figma variables that mirror the code one to one

Approach

Three levels, one rule, and the proof that it holds.

Three levels, and components read only the third

Level 1 is the palette: raw values, named by value, never read by a component. Level 2 is a scope per source, [data-source="youtube"], that remaps six contextual tokens. Level 3 is what the card reads: border-card, icon-card, bkg-pill and so on. A source lives in the scope, never in a token name. If it were in the name, the card would need a condition to pick it, and every new source would touch the component.

The proof, live

This is a demonstration card written for this page, with the same architecture and the same values. Change the source: six colours follow, the rating box doesn't, and the component code contains no colour name. In the product, a search for any source name inside the components, for colour purposes, returns nothing.

Lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod tempor
YouTube · AUTHOR · SAVED 7 NOV 26
ShortMediumOriginal

Lorem ipsum dolor sit amet consectetur adipiscing elit sed do eiusmod tempor incididunt ut labore et dolore magna aliqua ut enim ad minim veniam quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

ElitConsectetur DoloresIpsum Ligula
RATED: LOVE ITREAD IN FOCUS

Resolved value (scope: YouTube)

--demo-color-border-card
--demo-color-border-card-hover
--demo-color-border-card-read
--demo-color-icon-card
--demo-color-bkg-pill
--demo-color-ring-card-active

A token is chosen for its role, never for its value

Two things that look the same today get two tokens if they do different jobs, because they will diverge. The rating label and the meta line are both small monospace capitals; they are two roles, so two tokens. The rule cuts both ways: a new role gets a new token even when its value already exists.

Component, pattern, guideline or one-off

One question decides: is it reused in more than one place? When the system was only the card, that test gave four components: source icon, tab selector, chip and rating row. Header, tab row, content area and footer are used once, so they stay inside the card. "Confirm before delete, inside the card" is a pattern. "Only source colours go through tokens" is a guideline. As the product grew to the header, the chat and the onboarding, the same test gave 38 components, each with its states, and every one of them is in production.

Figma came last, generated from the product

Alone, the product was the fastest place to decide. The Figma library was generated from the code afterwards, so the two cannot disagree: every variable mirrors a token, every component carries an IN CODE label, the component library follows Atomic Design (tokens, atoms, molecules, organisms, templates), and the token page in the app is read from the stylesheet itself, with a drift check that flags any token without a documented role.

Key Decisions & Trade-offs

What I chose, what I gave up, and what it bought.

Where the source lives

Options Considered
1. In the token name (border-card-youtube)
2. In a scope ([data-source]) that remaps the same names
Why We Chose
A name per source puts a condition in every component. A scope keeps the component ignorant and makes a new source a CSS block.
What it bought

Two levels or three

Options Considered
1. Palette + semantic
2. Palette + scope + contextual
Why We Chose
With two levels the theme axis has nowhere to go but the component. The middle level is small (six tokens per source) and is the whole theming mechanism.
What it bought

Lightness over nominal level

Options Considered
1. Every source at the same Tailwind step
2. Align on perceived lightness
Why We Chose
Four sources sit at step 400. GitHub at 400 was ten L* points lighter than the cluster, so it is at 500. The palette aligns on how light the colour looks, not on what the scale calls it.
What it bought

Colour is never the only signal

Options Considered
1. Colour alone
2. Colour plus a text badge; read/unread on a different channel
Why We Chose
Each card carries a short text label of its source, so it works in greyscale and with colour blindness. Read and unread never share the colour channel with the source.
What it bought

What not to tokenise

Options Considered
1. Full type scale, spacing and radius tokens
2. Only roles the product uses
Why We Chose
A single product does not justify a scale. Type tokens are per role; spacing and radius are not tokenised yet. The day a second surface needs them is the day they get built, everywhere at once.
What it bought

How many components

Options Considered
1. A component per visual element
2. Only what passes the reuse test
Why We Chose
Parts used once stay where they are. Promoting them would add files, variants and maintenance for zero reuse. Nothing in the library is speculative: a component exists because the product ships it.
What it bought

What I Learned

The work that disappeared was the drawing. The work that stayed was deciding.

Generating Figma from the product removed hours of redrawing. It did not remove a single decision: which states exist, which parts earn a component, what stays out. Those were made before any tool ran.

A known outlier beats a hidden one

The article amber sits fourteen L* points above the other sources, and it is the most frequent colour in the feed, next to the brand peach. It is not a defect today. It is written down as the worst case for any dark theme, with the ticket that will pay for it. A palette that is honest about its weak point is easier to govern than one that looks perfect.

Alone, the product is the fastest place to decide. With a team, that changes.

Working solo, Figma was a canvas for early ideas and the code was the source of truth. Add one more designer and the Figma file stops being optional: it is where people see the system without opening the product. The right setup depends on who has to reach the decisions, not on the tool.

Figma can hold the truth. It cannot be the bottleneck.

If a decision lives somewhere only one role can open, that role becomes the bottleneck. The question is not which tool holds the truth; it is who can reach it.

See the tokens, or talk about them

The product is live. If you run a design system and are deciding how much of it one product really needs, I'd like to compare notes.

© 2026 Giacomo Bianchi.

Italian by birth. Product leader by craft. Global by vocation.

Barcelona • Open to MENA, Europe & Remote