1. 04The UI kit: primitives, styles, and interactions
  2. 05Building components with clear responsibilities
  3. 06Shared abstractions versus local composition
  4. 07When a component library needs an escape hatch
  5. 08Third-party UI dependencies are infrastructure too

Component libraries and UI infrastructure

06

Shared abstractions versus local composition

A premature shared component makes every local change span features. Duplicate until the mechanic is durable enough to extract.

By Eyal Ellenbogen August 10, 2026 4 min read

When two distinct features happen to look similar in design mocks, the immediate instinct in code review is to combine them into a reusable component. If the activity log feature and the account settings feature both display a sidebar with a filterable list and an action button, someone inevitably suggests extracting that layout into a reusable SharedPanel.

That extraction feels like disciplined engineering because it eliminates a dozen lines of duplicated markup. But two screens that look alike today rarely stay identical for long. Within a few sprints, the activity log needs an approval workflow, while the account settings feature needs a custom empty state. What started as visual similarity quietly turns into a shared bottleneck.

Ask whether the decision outlives the feature

A useful test before extracting a shared component is to ask whether the abstraction would still make sense if one of those features never shipped.

Platform spacing tokens, accessible dialogs, and keyboard navigation primitives would. They represent durable design system rules. A layout component created solely because two views happened to share a sidebar layout would not. If deleting one feature leaves that abstraction with only one consumer and an awkward name that no longer represents a real pattern, keep the composition local. Similarity in a mock usually just means two designers drew inspiration from the same wireframe.

Building components with clear responsibilities limits what a shared API should promise. The earlier question is whether that shared API needs to exist at all.

The cost is no longer a local edit

Once SharedPanel lives in shared infrastructure, changes cease to be local. When the account settings feature needs to adjust panel padding, reorder footer actions, or add a sticky header for smaller screens, the edit cannot stay confined to its feature folder.

Because the activity log feature shares that exact component, every small styling adjustment creates an unintended ripple effect. A routine layout tweak now demands cross-team reviews, synchronized release schedules, and regression testing across screens the author never intended to touch. The markup was deduplicated, but shipping velocity took the hit.

Share the mechanics, keep the arrangement local

The alternative is to separate durable structural mechanics from the domain composition inside them.

This does not mean re-authoring responsive flexbox rules and container queries in every feature. Recurring spatial patterns such as a header bar, a split pane, or a responsive sidebar shell are legitimate shared layout primitives. The distinction is what that primitive owns:

// A shared layout primitive using compound slots:
<SidebarLayout>
  <SidebarLayout.Aside>
    <ActivityFilters />
  </SidebarLayout.Aside>
  <SidebarLayout.Main>
    <ActivityList />
  </SidebarLayout.Main>
</SidebarLayout>

The layout component owns only spatial arrangement: responsive breakpoints, scroll boundaries, column gaps, and slot placement. It has no domain opinions. It does not know whether the sidebar contains filters, navigation links, or an account summary.

Both features can share the structural SidebarLayout from the UI kit. What remains authored locally inside each feature directory is the composition: the specific buttons, tables, and state machines that occupy those slots. When one feature needs a custom action bar or a new confirmation drawer, engineers modify their own local composition without touching the shared layout shell or affecting neighboring routes.

When to actually extract

We should leave local versions in place until changing one genuinely requires changing the other for a reason the design system can clearly state. Duplicated markup between two views is minor maintenance. An ad-hoc shared component that forces multiple teams into an ongoing coordination tax is technical debt paid on every PR. Sandi Metz's “The Wrong Abstraction” explores why restoring duplication is often the fastest way forward.

If shipping a routine layout change in one screen requires negotiating with another team or navigating unrelated test suites to avoid collateral breakage, the abstraction was extracted too early. Put the copies back.