Design Systems Engineering: Component Libraries That Ship
You know this story because you’ve lived it. Your organization spent over a year building a design system. Designers poured months into the Figma library. The launch blog post was great. And within six months, only two product teams were actually using it. Everyone else forked their own button components because the official version didn’t support the variants they needed, a patch update broke their layouts with no changelog, and the contribution process required a review queue that averaged six weeks with nobody assigned to run it.
Here’s the uncomfortable part: the design system wasn’t abandoned because the Figma files were bad. It was abandoned because nobody treated the component library as production infrastructure. No semantic versioning. No visual regression tests. No contribution path that didn’t bottleneck on a single team with no bandwidth. The design problem was solved. The engineering problem was never started.
Design Tokens as the Foundation
If you take one thing from this article, make it this: design tokens must be the source of truth for all visual decisions. Not #1A2980 but --color-brand-primary. Not 16px but --spacing-md. Token values can change freely. Semantic names should not.
Style Dictionary is the standard transformation layer. A single JSON or YAML token source generates CSS custom properties for web, Swift UIColor constants for iOS, and Android XML resources for native Android. One commit, every platform updated. Without this pipeline, teams burn 4-8 hours per platform synchronizing visual changes manually, introducing subtle mismatches each time. With token-driven transformation, a change that touches 3 platforms becomes a 15-minute PR that a single engineer handles.
This is where most teams mess up the naming. A --color-interactive-primary token lets you change the entire interactive palette by updating one value. A --color-blue-500 token does not, because “blue-500” describes what the color looks like, not what it means. The moment you need dark mode, white-label theming, or seasonal variations, that distinction will bite you. Semantic tokens let you change token values per theme. Literal tokens force consumers to change their code.
The transformation pipeline makes this architecture operational. Here’s the flow that actually works in production: a single token source feeds Style Dictionary, which generates platform-specific outputs for web, iOS, and Android simultaneously. Change a design decision in the source and it propagates to every platform in one commit.
Component Library Versioning
Tokens are the foundation. But without proper versioning, the component library built on top of them will still cause chaos. Let’s talk about why.
Components shipped as a versioned npm package give product teams explicit control over when they adopt updates. An unversioned system where teams pull directly from main is a ticking time bomb. Any design system commit can break product builds immediately with no warning and no rollback path.
Semantic versioning makes the contract explicit. Patch versions are safe to adopt automatically. Minor versions add capabilities without breaking existing usage. Major versions contain breaking changes that require migration effort. But here’s the trap: “non-breaking” is harder to define for component libraries than for a REST API. A default spacing change doesn’t break compilation but absolutely breaks visual layout. A renamed prop is a breaking change that frequently gets misclassified as minor because “the component still renders.”
Changesets tooling solves this. It forces contributors to explicitly categorize every change as patch, minor, or major and write a human-readable description. This discipline makes semantic versioning reliable rather than aspirational. Without it, you will ship a “patch” that changes button padding and break 10 teams’ layouts on their next npm update. It happens. More than once.
Major version migrations are where design system adoption either succeeds or dies. Don’t force a hard cutover. Run parallel major versions (v3 and v4 simultaneously) during a 3-6 month migration period and give product teams a deadline with a ramp. Codemods that automate the mechanical parts (renaming props, updating import paths, changing component composition patterns) reduce migration effort from weeks to hours for most consumers. Teams using codemods report 80-90% of migration changes handled automatically.
Visual Regression Testing
Versioning protects consumers from surprise. But it doesn’t tell you whether a change looks right. That’s where visual regression testing earns its keep.
Here’s a real pattern we’ve seen play out: a single spacing change in a shared Button component silently broke layouts in 10 consuming applications across 4 product teams. Without visual regression testing, those breaks surfaced 3 weeks later during a production release. The root cause took 6 hours to trace back to a “safe” patch version bump that nobody thought to visually verify.
Chromatic and Percy solve this. They capture screenshots of every component across all states and variants defined in your Storybook stories. Every PR generates a pixel-level comparison against the approved baseline. Reviewers see exactly what changed visually. Intentional changes get approved as the new baseline. Regressions get caught before merge. No more detective work three weeks after the fact.
But here’s the catch: coverage is only as good as your stories. A Button component with stories for default, primary, secondary, disabled, and loading states has those five visual baselines. No story for the error state? No visual baseline. That means a visual regression in the error state goes completely undetected. Track story completeness as a first-class metric alongside code coverage. Mature UI/UX engineering treats stories as the test surface: every state a component can render should have a story, especially the edge cases where layouts commonly break. Very long text. Empty content. Maximum item count. Right-to-left locales. Those edge case stories are exactly where visual regressions hide.
Accessibility as a CI Gate
Visual regression catches what your eyes would miss. But there’s a whole category of breakage that screenshots won’t reveal: accessibility.
Accessibility requirements documented as guidelines get ignored under deadline pressure. Every single time. Accessibility requirements enforced by CI gates don’t. This is not philosophical. It’s the difference between a component library that ships accessible components and one that merely aspires to.
Axe-core integrated into Storybook’s test runner automatically checks stories for WCAG violations on every PR: color contrast ratios below 4.5:1, missing ARIA labels, improper heading hierarchy, interactive elements without keyboard focus management. A component that fails axe-core doesn’t merge. Full stop. No exceptions for “we’ll fix it later.”
Automated axe-core catches roughly 30-40% of WCAG issues, which is the portion that can be mechanically verified. The rest (logical reading order, complex keyboard interaction patterns, screen reader announcement quality for dynamic content, focus trap behavior in modals) requires a human. So document specific manual acceptance criteria for each interactive component type. When a reviewer sees “Modal: verify focus traps correctly on open, returns focus on close, Escape key closes” they have a concrete checklist rather than a vague “check accessibility.” For organizations serious about accessibility engineering, these criteria are non-negotiable parts of the definition of done.
Governance Without Bottleneck
You can have perfect tokens, solid versioning, visual regression, and accessibility gates. None of it matters if the governance model creates a bottleneck that drives teams away.
The single-team-owns-everything model creates a failure pattern so predictable it’s almost scripted. Product teams wait months for design system resources to build the components they need today. The request backlog grows. Teams build locally because they can’t wait. The design system drifts away from actual product patterns. Within a year, nobody uses it.
Here’s the model that actually works: treat the design system like platform infrastructure. The design system team owns the platform, the standards, and a core set of 30-50 foundational components. Product teams contribute domain-specific components that meet the quality bar. The contribution criteria (accessibility gates pass, documentation coverage meets threshold, visual regression baselines exist) are enforced by CI, not by a committee that meets biweekly. A product team that needs a DataTable component builds it to the required standard and gets it into the shared library without waiting for design system team capacity. No ticket. No queue. Just a PR that passes the gates.
Write Architecture Decision Records for significant choices (why tokens are structured this way, what the rationale was for the v3 breaking change, why the component API uses composition over configuration). Without them, the same decisions get relitigated every quarter and contributors make inconsistent choices because they don’t have context. This pairs naturally with the CI/CD practices that make automated quality gates the enforcer rather than manual review bottlenecks.
The design systems that die are the ones treated as design artifacts. The ones that survive are treated as production infrastructure with versioning, testing, and contribution paths that work at engineering speed. A Figma file and a style guide are where you start. A versioned, tested, CI-gated component library with federated governance is what actually ships consistent UI at scale. Build the engineering, or watch the adoption curve flatline.