All writing

Architecture · Design Systems

The Case for a Thin Wrapper Layer Around Every UI Library

Calling a third-party component library directly from feature code feels efficient right up until the library needs to change.

Jaymin Maheta 7 min read
Share:
Component library architecture on screen

The library was never the plan — it was a decision made once

Every enterprise app I've worked on has migrated its UI library at least once — Material to PrimeNG, or a major version bump that changed component APIs enough to count as a new library. Each time, the pain was directly proportional to how many places in the codebase called that library's components directly.

A thin wrapper — your own `Button`, `DataTable`, `Modal` components that internally render the third-party ones — turns a library swap from "touch every screen" into "rewrite one folder."

What "thin" actually means

Expose your API, not the library's

Your `AppDataTable` should accept props that make sense for your product — not forward every prop PrimeNG's table happens to support. A smaller surface area is what makes a future swap tractable.

Don't rebuild the library inside the wrapper

The wrapper's job is to narrow and translate, not reimplement. If you're writing hundreds of lines per wrapped component, you've built a second library instead of a thin layer.

Centralize theming inside the wrapper

Design tokens, spacing, and variant props belong in the wrapper's implementation, so a rebrand or dark-mode pass touches one file per component type instead of every usage site.

Wrap what you use twice, not everything

Wrapping every primitive up front, including ones used once, is wasted effort. Wrap opportunistically — the second time a component pattern repeats is the right time to extract it.

Enforce the boundary with linting

An ESLint rule banning direct imports from the third-party package outside the wrapper folder turns "please use our wrapper" from a code-review nag into an automatic build failure.

Version the wrapper's breaking changes deliberately

When the wrapper's own API needs to change, treat it like a real library release — a changelog entry and a migration note — since dozens of screens now depend on it staying predictable.

The real payoff isn't the next migration

Teams sometimes skip this because "we're not planning to switch libraries." That's the wrong frame — the wrapper layer pays for itself long before any migration, because it's also where cross-cutting fixes live: the overlay z-index fix, the consistent loading-state pattern, the shared validation message format. Those changes hit one file instead of being copy-pasted across screens by whoever notices the bug first.

A library swap is just the most visible moment the investment shows up. The daily payoff is every smaller fix that didn't need a codebase-wide search-and-replace.

The takeaway

A thin wrapper layer around a UI library — narrow API, centralized theming, enforced by lint rules, built opportunistically rather than up front — turns both library migrations and everyday cross-cutting fixes into one-file changes instead of codebase-wide hunts. Build it the second a component pattern repeats, not after the third library swap teaches you the hard way.

Let's talk about your frontend