lan hoang

Refract Design System

OKLCH colour engine, about 130 components, motion system, live Studio, CI token checks2026

One design system that becomes a different product for each brand.

Overview

Problem
Every client project at Refract started by rebuilding the same palette, type scale and component kit.
What I did
I built one design system where a brand is a recipe of about fifteen values, with a colour engine that sets contrast itself and a live Studio to edit it in.
Outcome
Seven brands ship built in. Every brand passes WCAG 2.1 AA contrast on every build, and CI rejects hardcoded colours.

Context

Refract designs products for many clients, and every project started by rebuilding the same foundations. I wanted one system that could become a distinct product for each client, where a brand is one recipe the whole system reads from:

  • Colour two seed colours, expanded into the full palette.
  • Type display and body faces, the scale and the base size.
  • Shape corner radius, set separately for cards and controls.
  • Motion timing and bounce, stored as tokens.
  • Everything else space, elevation, borders, texture, icons, and light and dark modes.

Change one value and every component updates with it, live.

The problem

The kit had to turn into very different products while someone edited it live, and stay readable while they did. Low-contrast text was found on 83.9% of the top million home pages in 20261, so the system had to prevent it on its own.

Constraints

  • Clients can choose almost any brand colour, so contrast can't be left to whoever does the theming.
  • Broken input is normal in a colour tool: half-typed hex codes, old kits, stale links.
  • One edit rewrites about 240 CSS variables, and it has to keep up with a dragged slider.

Research

I looked at where our recent client projects spent their first weeks, then read the research on contrast failures and on keeping design systems current.

  1. 01

    Recolouring by hue breaks contrast

    Change a hue to rebrand and body text can drop below WCAG's 4.5:1 minimum2 without anyone noticing until it ships.

  2. 02

    Documentation goes stale

    Docs drift from the code once they're published. In zeroheight's 2026 survey of 147 practitioners, 20% said they measure documentation coverage3.

  3. 03

    Hue changes how heavy colour looks

    In HSL, yellow looks lighter than blue at the same lightness value, so a new hue changes how heavy and readable text looks4.

Aim

Colour, type, shape, motion, space, elevation and modes, versioned together. Edit any value and the system re-derives itself, live.

Exploration

I built the engine in OKLCH, where equal steps in lightness look even across hues5. In HSL they don't, so palettes built there have uneven contrast.

The person theming picks brand colours only. The engine derives every text colour from the background it sits on, so each one meets the contrast minimum.

Solution

Two seed colours become 79 swatches and 110 named tokens per mode, each checked for contrast, and about 130 components are built only from those tokens. The Studio re-themes them live.

Outcomes

  • Seven brands ship built in, and a new brand takes about fifteen values.
  • Text and control colours meet WCAG 2.1 AA in every brand, checked on every build.
  • About 130 components, 125 of them with live controls in the Studio.

Still in progress. More to come once it's public.