JournalArchitectureNov 22, 2024

The Component Library That Cut Our Codebase in Half.

Sixty percent faster delivery. Not from a new framework — from a disciplined system of reusable components built on Shadcn UI and a shared design contract.

11 Min Read
The Component Library That Cut Our Codebase in Half.

The codebase had a button problem. Not one button — seventeen. Seventeen variations of a clickable element, scattered across the application, each with slightly different padding, slightly different hover states, and completely different approaches to handling loading indicators. Some used a spinner. Some disabled themselves. One, memorably, changed its text to "Please wait..." in a font size that did not match anything else on the page.

This was not a design failure. It was an architecture failure. The application had been built feature-by-feature, sprint-by-sprint, by developers who were each solving the immediate problem in front of them. Nobody was wrong. But the cumulative effect was a codebase where every new feature required rebuilding primitives that already existed — just not in a form that could be reused.

I had seen this pattern before, at every company I had worked at. The solution was always discussed in retrospectives and rarely executed: build a component library. The reason it rarely happened was not lack of will — it was lack of a viable starting point. Building a design system from scratch is a months-long project. We did not have months. We had a product roadmap that expected features next sprint.

Shadcn UI changed the equation. Instead of building primitives from scratch, we started with a set of accessible, unstyled components and layered our design language on top. The key insight was that Shadcn is not a dependency — it is a starting point. The components live in your codebase, under your control. You own them. You modify them. You extend them.

The first week was infrastructure. I set up a component directory with a clear taxonomy: primitives (Button, Input, Badge), composites (DataTable, FormField, StatusCard), and patterns (PageHeader, EmptyState, ConfirmationDialog). Each level built on the one below it. Primitives had no business logic. Composites combined primitives with layout. Patterns combined composites with domain-specific behavior.

The second week was migration. We replaced the seventeen buttons with one. We replaced the nine different card layouts with three variants of a single Card component. We replaced the inline form validation that was copy-pasted across twelve forms with a FormField wrapper that handled labels, errors, and help text in one place. Each migration was a pull request. Each pull request deleted more code than it added.

By the third week, velocity shifted. A developer building a new settings page reached for existing components instead of creating new ones. A feature that would have taken three days took one. Not because the developer was faster — because the decisions had already been made. Spacing, typography, interaction patterns, error states — all codified in the library.

The metrics told the story. Development velocity — measured as story points delivered per sprint — increased by roughly sixty percent over the following quarter. Code duplication, tracked by our linting rules, dropped by half. But the most significant change was qualitative: design consistency. The application started looking like a single product instead of a collection of features built by different people at different times.

The discipline that made this work was not technical — it was organizational. Every new component went through a review process. Does this belong in the library, or is it feature-specific? If it belongs, at which level — primitive, composite, or pattern? Is the API minimal enough to be reusable, but flexible enough to handle foreseeable variations? These questions slowed down individual contributions by minutes but saved the team hours of future duplication.

The component library is not finished. It never will be. It grows with the product, adapts to new requirements, and occasionally retires components that no longer serve a purpose. But the foundation — the taxonomy, the review process, the shared understanding that every component is a contract — that endures. And it is, quietly, the most valuable code in the entire repository.