Skip to content

PATTERN Cited by 1 source

Shared UI-kit as internal npm package

Problem

In a micro-frontend deployment, each remote is owned by a different team. If every team re-creates primitive UI components (buttons, modals, inputs, typography, form controls), three things happen:

  1. Design drift. Buttons look and behave subtly different across remotes; the portal feels like N stitched applications, not one product.
  2. Duplicated work. Every new team's first sprint is "build a button".
  3. Design updates are O(N). Changing the primary-button hover state means N pull requests across N repos.

Solution

Publish a shared UI-kit as an internal npm package. The kit contains reusable components — buttons, modals, inputs, typography, layout primitives — along with design tokens (colours, spacing, typography scale). Every remote depends on the same package version; design updates flow out by bumping a single dependency across remotes.

The package is typically:

  • Internal — published to a private npm registry or a monorepo workspace, not to public npm.
  • Versioned semantically — patch/minor/major discipline so remotes can opt into risky changes.
  • Owned by a design-system / platform team — not any one feature team.
  • Peer-dependent on React / React-DOM — shared as a singleton across host + remotes (see concepts/shared-singleton-dependency).

In a Module-Federation deployment the UI-kit is usually bundled into each remote (static-linked via npm), not shared at runtime via Module Federation. The runtime-shared libraries are the heavy stateful ones (React, state management), not small composable UI primitives.

Trade-offs

Pro - One design language. Visual + behavioural consistency across remotes without per-team re-implementation. - Cheap design updates. Central change propagates via dependency bump. - Faster team onboarding. New teams don't rebuild primitives. - Common accessibility story. Button / modal focus trap / ARIA semantics are implemented once.

Con - Version skew. Remotes on different kit versions can render visually divergent screens simultaneously; the design team must manage coordinated upgrades for major changes. - Platform-team bottleneck. Feature teams wanting a new primitive go through the UI-kit team's roadmap. - Bundle-size repetition. Each remote bundles its own copy of the UI-kit — duplicated code across federation boundaries unless the kit is also marked as a shared library in Module Federation config. - Does not solve composite pages. Shared primitives compose into screen-level layouts; that layer still needs coordination (or it drifts again at a higher altitude).

Relation to broader design-system patterns

Sibling pattern: patterns/design-system-component-library-cross-platform — the same idea generalised across web + iOS + Android (e.g. Yelp CHAOS, Zalando Appcraft). The internal-npm variant is the web-only instance, typically sufficient for a browser-altitude micro-frontend deployment.

Seen in

  • sources/2024-10-16-zalando-building-a-modular-portal-with-webpack-module-federation — canonical wiki instance. Zalando's Logistics Portal publishes "a shared UI-kit library … packaged as an internal npm module and distributed across all teams. It provides a set of reusable components, such as buttons, modals, input fields, and typography, all following the same design language and style guidelines." The team's own framing of the value: "any design updates could be applied centrally within the UI-kit and propagated across all applications, ensuring the portal always maintained a cohesive and up-to-date look and feel." 11 apps / 4 teams share one UI-kit.
Last updated · 550 distilled / 1,221 read