← Back to Blogs
Building Scalable React Component Libraries in Production Fintech

Building Scalable React Component Libraries in Production Fintech

How I architected reusable UI systems at WealthHat that improved development velocity by 25% across financial advisory modules — patterns for tokens, composition, and team adoption.

Why component libraries fail in fintech

Most frontend teams start with good intentions: a Button, a Card, maybe a DataTable. Six months later, you have three versions of each, inconsistent spacing, and engineers copying JSX from Slack threads.

At WealthHat, I led frontend work on a centralized client portal where advisors manage assets, goals, and planning workflows across multiple modules. The product surface grew fast. Without a deliberate component strategy, every feature would have become a one-off — slow to ship, expensive to test, and risky in a regulated financial context.

The goal was not a Storybook vanity project. It was a production system that could accelerate delivery, enforce accessibility, reduce regression risk, and scale with TypeScript contracts. We measured success in velocity: reusable UI components improved development speed by roughly 25% across advisory modules once adoption stabilized.


Start with primitives, not pages

The biggest mistake I see is building page components first and calling that a design system.

We inverted the approach:

  1. Design tokens — color, spacing, typography
  2. PrimitivesText, Stack, Surface, IconButton
  3. PatternsFormField, MetricTile, EmptyState, ConfirmDialog
  4. Domain componentsAssetAllocationChart, GoalProgressCard

Domain components compose patterns. Patterns compose primitives. Pages compose domain components. A junior engineer could ship a new advisory screen using existing patterns without inventing layout logic from scratch.


TypeScript as your API contract

In fintech UIs, ambiguous props create bugs that reach users. We treated every exported component like a public API:

type MetricTileProps = {
  label: string;
  value: string;
  trend?: { direction: "up" | "down" | "flat"; label: string };
  loading?: boolean;
};

export function MetricTile({ label, value, trend, loading = false }: MetricTileProps) {
  if (loading) return <MetricTileSkeleton />;
  return (
    <Surface padding="md" data-testid="metric-tile">
      <Text variant="caption">{label}</Text>
      <Text variant="display">{value}</Text>
      {trend && <TrendBadge direction={trend.direction} label={trend.label} />}
    </Surface>
  );
}

Strict props eliminate an entire class of runtime errors. Pair this with React Testing Library tests that assert behavior, not implementation details.


Composition over configuration

Configurable mega-components with dozens of boolean props become unmaintainable. We preferred compound components:

<DataTable>
  <DataTable.Toolbar>
    <SearchInput />
    <FilterMenu />
  </DataTable.Toolbar>
  <DataTable.Body columns={columns} rows={rows} />
  <DataTable.Pagination />
</DataTable>

Compound components keep APIs discoverable and let teams extend behavior without forking the library.


Accessibility is not optional

Advisors and clients rely on keyboard navigation and screen readers. Every pattern shipped with focus management for dialogs, aria-live regions for async portfolio updates, and visible focus rings aligned to brand colors.


Versioning and adoption

Breaking changes kill adoption. Our rules: patch for fixes, minor for additive APIs, major only with migration notes. I ran pairing sessions with three junior developers on component usage, which reduced code review cycles by ~20%.


Key takeaways

  1. Build primitives → patterns → domain layers, not page components first
  2. Treat TypeScript props as a contract; test behavior with RTL
  3. Measure adoption through velocity and review time, not component count
  4. In regulated domains, accessibility and consistency are features, not polish