All work
Design systemsB2B

One design language for three products

Company
Updater
Role
Lead designer, built in code
Scope
3 products + partner themes
Users
Internal product teams
Year
2025

Three products had drifted apart. A consumer app, a property manager tool and a set of embedded partner buyflows, each with its own idea of what grey meant and how far a shadow should fall. The obvious fix was a new component library. The problem with that fix is that every team would have had to stop shipping to adopt it.

The type scale in Storybook, primitives and semantic tokens side by side.
Three layers. Primitives hold raw values, semantic tokens describe intent, and the existing theme wires them into the component library.

Two decisions that shaped it

01

A layer on top, not a rewrite

Polaris is a semantic token layer added over the component library that already existed, not a replacement for it. Every public import path stayed valid, so no team had to pause work to adopt it. Components migrate one at a time in small pull requests, and a product that has not migrated yet still builds and ships. A rewrite would have been cleaner on paper and would have taken a year nobody was willing to give it.

02

Name tokens for intent, not for value

Tokens read as category, element, variant, state, so a component asks for text.color.secondary rather than gray700. Components never reference the palette directly. It is a small rule that decides whether a system holds: once a component names an intent instead of a colour, the value behind it can change per surface, per brand or per theme without touching the component at all.

Checkbox and radio states in Storybook. The focus ring is a lighter shared colour across form controls, not a match to the fill.

A second checkbox, not a replaced one

CheckboxV2 ships alongside the original, which is unchanged and still in use, and screens migrate to it one at a time. The original exposed three sizes and let the checked fill be green, blue or white, which is how it drifted across the app. The new one is always 24px, resolves every colour through a semantic token with no palette references or raw hex left in the component, and adds a focus ring the original never had. Radio followed the same pattern. The same argument as the token layer, one level down.

How I worked

Storybook as the contract

Every foundation documented with Primitives, Semantic and Legacy side by side, so the migration state is visible rather than tribal knowledge.

Small, reviewable PRs

One foundation per pull request, each with what changed, why, and what to check.

Decision log

Collisions and deferrals written down as they came up, including the ones left unresolved.

What I would change

Radius is unfinished. The scale Polaris wanted collides with a legacy key of the same name at a different value, so rather than silently change every rounded corner in production I shipped the primitives and left the semantic layer out until the intent is settled. The Figma tokens have also drifted behind the code. A system that documents itself in two places will always drift, and the honest fix is generating one from the other.

Design system to stand up or rescue?

Next: Property managers brand it themselves now