
Design Systems · Accessibility
Authoring a Production Design System From Zero
With no dedicated design-systems team to build one, I sole-authored a versioned, token-based component library now backing a four-codebase ecosystem, taking it from zero to a published package in about 3 months with 68 components, WCAG AA, and a 90% coverage gate built into CI.
- Company
- Prudentia Sciences
- Role
- Senior → Principal Product Designer
- Timeline
- Mar 2025 – present
- Version
- v0.27.0
Context
Prudentia's product surface had grown into two end-user apps and two shared feature libraries, each built by whichever team touched it first. There was no dedicated design-systems team to own consistency across them, and none was getting funded. I took it on myself, alongside my own shipping product work, and built the thing the org needed but hadn't staffed.
Zero to a published, versioned package.
3mo
From zero to first release
68
Components shipped
AA
WCAG conformance
90%
Coverage gate on every merge
Accessibility checks run in CI, not in review.
Problem
Multiple front-ends were each re-implementing their own overlays, tables, and theming. There was no shared token contract, no accessibility floor, and no release discipline, and no team whose job it was to impose one. At a life-sciences company, that inconsistency isn't just visual noise: the same evaluation workflow could look and behave differently depending on which app a scientist happened to be in, which is exactly the kind of drift that erodes trust in regulator-facing tools. The mandate I set for myself: build a single source of truth that teams would actually adopt, authored alongside shipping product work rather than as a separate initiative someone had to wait on.
Process
Architecture first: product code never touches a raw palette value. It consumes intent, and the system resolves the rest, which is what makes theming and accessibility solvable in one place instead of in every app.
Tier 1 · Primitives
Raw palette, generated from Figma, never hand-edited
Tier 2 · Semantic tokens
Intent-based, each with a subtle / subtlest / hovered / pressed ramp
Tier 3 · Tailwind @theme map
Clean utility-facing names, one indirection from the semantic layer
a11y override layer
A hand-authored contrast layer sits after the Figma export, so a token re-export can't silently regress it. Ships WCAG 2.1 AA, with AAA where the palette allows.
Dark mode = one remap
A single theme class remaps Tier 2 only. Because components consume Tier 3, the whole system flips with zero per-component work anywhere else in the tree.
Tier 2, the semantic layer: each intent gets a hovered, pressed, subtle, and subtlest state ramp, not a color a component picks for itself.
Default
Hovered
Pressed
Subtle
Subtlest
brand
danger
warning
success
info
The same tokens drive every interactive state, so a primary action, a secondary action, and an icon button all stay in sync by construction instead of by convention.
Default
Hover
Pressed
Focus
Disabled
Primary
SaveSaveSaveSaveSaveSecondary
CancelCancelCancelCancelCancelIcon
Governance without a governance team. Adoption, not architecture, was the real risk. I gave the design-system repo its own Claude instruction file, written to operate like a seasoned UX/UI developer: WCAG AA as table stakes on every contribution, not a nice-to-have. Migration ran the same way, built into the normal rhythm of work rather than a dedicated sprint: hand-rolled components and hardcoded hex values got swapped for the system's tokens whenever a developer touched that code for product work, so the legacy surface shrank gradually instead of blocking on a big-bang rewrite.
Governance had to be built, not just tooling. I stood up recurring design-system rituals and review channels that gave other designers and engineers a place to propose changes and align on adoption before it landed.
All checks passed
5 / 5Rituals and review channels are where people agree on a change before it reaches this gate.
Motion as a token, not a per-component decision.
The same principle as color, applied to movement: duration and easing live as tokens, not per-component decisions, aliased through the theme layer so one default sets the system's tempo everywhere at once. The tokens below are shown in motion, not just listed.
Duration, a 3-step tempo scale
Easing, a directional pair
ease-enter · decelerate (fast start, settles in)
ease-exit · accelerate (slow start, speeds away)
Reduced motion, a library-wide kill-switch
A single prefers-reduced-motion rule neutralizes every animation and transition centrally, so no individual component can forget to respect it.
Coverage isn't complete yet: one composite animation token exists so far, a brand-mark toggle flourish, and the reduced-motion switch currently also freezes looping loaders, a known trade-off the code calls out directly rather than leaves silent, with a scoped opt-out planned next.
Solution
A versioned, auto-released component library published to a private
registry, built on Tailwind v4's @theme, and Storybook with axe-core
in CI so a violation fails the build instead of shipping. Radix
primitives bridged early accessibility needs, but the goal was never to
depend on it long-term: the plan is to move off Radix entirely as the
system's own primitives mature. Dark mode is a
single remap of the semantic tier, not a per-component fix: a full
dark-mode correction elsewhere in the ecosystem landed in 2 files and 23
lines, because the semantic tokens absorbed the rest.

Before: 4 separate forks, each re-solving overlays and theming locally, with dark mode re-fixed screen by screen. One app's refactor onto the system, in a single PR:
111
Files moved onto the system
−562
Net lines removed
4
Duplicated overlay primitives deleted
refactor: consolidate overlays onto @prudentia/ui
MergedDialog.tsx
DeletedPopover.tsx
DeletedTooltip.tsx
DeletedComboBox.tsx
DeletedOutcome
The design system is the substrate two feature libraries are built on, which then compose back into the apps.
@prudentia/ui
v0.27.0 · 68 components
End-user app
Consumer
End-user app
Consumer
Feature-UI library
Peer-depends
Feature-UI library
Peer-depends
~1wk
repo to first release
260
commits
70
test files
15
Radix primitives wrapped
First component published within a week of the repo's creation. The package now sits at v0.27.0 and is the foundation of a four-codebase ecosystem: two end-user apps and two shared feature-UI libraries that peer-depend on it and compose back into those apps. Six front-end engineers build on it directly, and joined the same rituals that govern it, not just the code. Roughly 250 product source files import the system directly across the two apps alone, with Button, Dialog, and Tooltip the most broadly adopted primitives.
Across 260 commits and 70 test files, the org went from four separate teams each re-solving the same problems to one shared contract they build on instead of around, with noticeably less back-and-forth between design and engineering catching the inconsistencies a shared system now prevents by construction.