40% Faster Feature Delivery Through Component Library Restructuring
Four button components, three modal wrappers, and 200+ files in a flat directory. Time to fix it.
Client name withheld under NDA. Industry, scope, and results are accurate.
The Challenge
The codebase had over 200 components in a flat src/components/ directory. Built by a rotating cast of contractors over 18 months, and it showed:
- Four different button components:
Button,Btn,PrimaryButton,ActionButton. Three modal wrappers. Two form-input abstractions. None shared a consistent API. - Zero design tokens. Colors, spacing, and typography were hard-coded as hex strings and pixel values everywhere. Want to change the brand's primary color? That's a project-wide find-and-replace with manual verification.
- Painful onboarding. New developers spent their first two weeks figuring out which component to use for any given pattern. Most gave up and created yet another variant. Average time-to-first-meaningful-PR: three weeks.
- "UI inconsistency" accounted for about 15% of the bug backlog. The design team was frustrated. Users noticed.
The VP of Engineering wanted this fixed without halting feature delivery. Fair constraint, but it meant I couldn't just start deleting things.
The Approach
I started with an inventory. A grep-based script that counted every component, its props interface, and how many times it was imported. Screenshotted each one and dumped it all into a spreadsheet — 200+ entries, grouped into four categories: primitives (Button, Input, Text), composites (Card, Modal, Dropdown), layout (Stack, Grid, Container), and domain-specific (PatientCard, AppointmentRow). The duplicates were immediately obvious.
Before touching a single component, I sat down with the design team and built a design-token foundation. Colors, spacing, typography, border-radius, shadows — all defined as CSS custom properties and plugged into a Tailwind theme config. One source of truth that both Figma and code could reference by the same name. This step was unsexy but critical: without it, any refactoring would just create a different kind of inconsistency.
Then the consolidation work, in priority order — highest-usage primitives first. For each group of duplicates:
- Designed a unified props API that covered every existing use case.
- Built the canonical component with full TypeScript generics,
forwardRefsupport, and variants viaclass-variance-authority. - Wrote a codemod (
jscodeshift) that automatically migrated call sites from deprecated components to the new one. - Added visual regression tests through Chromatic to catch unintended style changes.
The codemods were key. Feature teams never had to pause — the migrations ran as automated PRs that each team reviewed and merged on their own schedule. No feature freeze, no coordination overhead.
Finally, a Storybook instance with every canonical component documented: usage examples, props tables, do/don't guidelines, accessibility notes. Three "recipe" pages for common composition patterns (form layouts, data tables, empty states). And an ADR template so the team would document future component decisions — the kind of process that prevents the mess from coming back.
Tech Stack
The Results
The impact showed up in the first sprint after rollout:
- Feature velocity: +40% (story points per sprint, averaged over six sprints before vs. after). Engineers stopped spending time on "which component do I use?" decisions.
- UI bug reports: ~12 per sprint → ~4. The consolidated components encoded correct accessibility, focus management, and responsive behavior by default.
- Onboarding: 3 weeks → 1 week. Storybook + clear folder taxonomy meant new hires could ship meaningful PRs fast.
The design team noticed too — the "this doesn't match the Figma" back-and-forth virtually disappeared once both sides were using the same token names.
Six months later: 38 canonical components had grown to 52, all following the established patterns. Zero regressions to the duplicate-component problem.