Skip to content

FRONTEND SYSTEM DESIGN

Design a Large component library

Design a component library and its distribution/versioning strategy for dozens of consuming teams.

Large component library architecture diagram

THE INTERVIEW SEQUENCE

How to drive this discussion

01

Clarify scope

02

Set requirements

03

Draw data flow

04

Defend trade-offs

Start with the smallest coherent design. After the main path works, introduce failure, scale, accessibility, observability, and release strategy one constraint at a time.

01Concrete scale assumptions

Dozens of product teams consume React components on independent release schedules.

The library supports themes, internationalization, server rendering, and evergreen browsers with a declared support policy.

Accessibility conformance, typed APIs, and predictable upgrades are release gates rather than documentation promises.

Packages must remain tree-shakeable and avoid forcing duplicate framework or styling runtimes.

02Architecture decisions and rationale

Layer tokens, primitives, and composites

Stable design decisions flow into accessible behavior primitives and then opinionated product components without circular ownership.

Publish explicit package boundaries

Peer dependencies, exports, CSS ownership, and side-effect metadata protect bundle size and runtime compatibility.

Treat APIs as products

Semantic versioning, deprecations, migration guides, and codemods make distributed adoption operationally possible.

Test behavior, not snapshots alone

Interaction, accessibility, visual, type, SSR, and browser tests catch different classes of regression.

03Client contracts and data boundaries

Composable component API

Controlled and uncontrolled state, semantic callbacks, and stable slots support product needs without leaking internals.

TypeScript
type DialogProps = { open?: boolean; defaultOpen?: boolean;  onOpenChange?: (open: boolean) => void;  title: React.ReactNode; description?: React.ReactNode;  children: React.ReactNode; };// Focus, Escape, labelling, and portal behavior remain library-owned.

04Failure-mode analysis

Duplicate runtime dependency

Impact: Bundles grow or context breaks across copies.

Mitigation: Declare peers and export maps correctly, test consumer fixtures, and monitor installed dependency graphs.

CSS leaks or changes order

Impact: An upgrade silently changes product UI.

Mitigation: Scope layers, define injection order, test SSR/hydration, and avoid depending on consumer import accidents.

Accessibility regression

Impact: Keyboard or assistive-technology users lose a workflow.

Mitigation: Combine automated checks with interaction tests and manual AT coverage for high-risk primitives.

Breaking release spreads slowly

Impact: Teams stay pinned and the ecosystem fragments.

Mitigation: Canary real consumers, publish migrations and codemods, maintain a deprecation window, and track version adoption.

05Observability and operations

  • Track package and component adoption, version distribution, upgrade lag, deprecation use, and support incidents.
  • Gate bundle-size, public-type, visual-diff, accessibility, SSR, and interaction budgets in CI.
  • Run a matrix against supported React, browser, theme, locale, direction, and rendering environments.
  • Canary releases in representative applications and make rollback or dist-tag reversal immediate.

06Security and accessibility boundaries

  • Protect publishing with provenance, least-privilege tokens, review, dependency scanning, and an incident revocation path.
  • Accessible names, roles, focus, keyboard behavior, contrast, motion, zoom, and forced-colors support are component acceptance criteria.
  • Prefer semantic HTML; use ARIA only where native semantics cannot express the required interaction.
  • Document accessibility responsibilities shared with consumers, such as meaningful labels and heading hierarchy.

ANSOne full answer, start to finish

Drive the discussion yourself first. This is one strong answer delivered the way you would say it in the room — a model, not the only correct design.

This one is a distribution and versioning problem more than a components problem. The components are the easy part; the hard part is that dozens of teams consume them on their own schedules, so every decision is about not breaking those teams. Frame it around the monorepo, semantic versioning, and design tokens.

  1. Step 1 · Clarify

    Ask: 'How many consuming teams and applications? One framework or several? Do they all upgrade together or independently? And is there a design system with tokens already, or are we defining that too?' Assumptions: 'Dozens of teams, primarily one framework, teams upgrade on their own schedule, and we own the tokens as well.' Independent upgrades is the constraint that shapes everything.

  2. Step 2 · Requirements

    User-facing (the consuming developers): components that are accessible by default, themeable, and documented, that they can adopt without a big-bang migration. Hidden: a change must be shippable without forcing every team to update the same day, the bundle impact must be predictable, and breaking changes must come with a migration path.

  3. Step 3 · Monorepo with three things in it

    'One repository holds the component packages, a shared design-token package (colors, spacing, type as data, not hard-coded in each component), and a documentation and playground site built from the same source. Keeping them together means the docs cannot drift from the code and the tokens are the single place visual decisions live.'

  4. Step 4 · Headless-first components

    'Where it makes sense, components are built on composable headless primitives, so the behavior — keyboard handling, focus management, accessible roles — is separate from the visual styling. That makes them easier to theme and means the accessibility work is done once in the primitive, not re-litigated per skin.'

  5. Step 5 · Versioning and release discipline

    'Semantic versioning with automated changelog generation. Every change ships with a changeset declaring whether it is a patch, minor, or breaking. CI runs visual regression, unit, and accessibility tests against every component and gates the release. A breaking change is deprecated first with console warnings, ships with a migration guide and ideally a codemod, gets canaried against a few consumers, and only then goes out as a major after a declared window.'

  6. Step 6 · How teams adopt

    'Consuming teams update their dependency when they choose, guided by the changelog and by deprecation warnings that appear well before a breaking release. Nobody is forced to move on the library's schedule. The library owns interaction mechanics and controlled-state support; product data and business logic stay with the consumer.'

  7. Step 7 · Bundle and theming

    'Packages use ES module exports with accurate side-effect metadata and narrow entry points so consumers only ship what they import. Theming is semantic tokens — a component asks for surface and text, not a specific hex — so a new theme is a token file, not a component rewrite.'

How to close

'So: dozens of teams, independent upgrades, we own the tokens. A monorepo holds components, a token package, and docs from one source. Components are headless-first so behavior and accessibility are decoupled from styling. Semantic versioning with changesets, CI-gated visual and accessibility tests, and deprecate-migrate-canary-then-major for breaking changes. Teams adopt on their own schedule. The health signal I would watch: adoption rate and successful-upgrade rate, plus version fragmentation across consumers.'

QAInterview questions and model answers

The library owns interaction mechanics and supports controlled state; product data and business workflows remain with the consumer.

Primary references

DESIGN CHECKLIST

Build your answer from first principles

Use this checklist to rehearse the case without reading the worked answer above.

CLARIFYING QUESTIONS

Do not design yet. Use these questions to make hidden assumptions explicit and prevent solving the wrong problem.

  1. 01

    How many consuming applications/teams, and do they share a build system?

  2. 02

    Is theming/white-labeling required across consumers?

  3. 03

    What's the tolerance for breaking changes — one release train, or independent versioning per consumer?

  4. 04

    Is accessibility compliance a hard organizational requirement?

FUNCTIONAL REQUIREMENTS

These are the user-visible capabilities the design must support. They define the first version's scope.

  1. 01

    Provide a versioned, installable package (or set of packages) of shared UI components.

  2. 02

    Support theming so different consuming products can apply their own visual identity on top of shared behavior.

  3. 03

    Document each component's API, accessibility behavior, and usage guidance discoverably.

  4. 04

    Allow consumers to adopt updates incrementally rather than being forced onto every release immediately.

NON-FUNCTIONAL REQUIREMENTS

These qualities shape the architecture even though users do not click them directly: latency, resilience, accessibility, consistency, and scale.

  1. 01

    Backward compatibility guarantees clear enough that consuming teams can trust semantic versioning.

  2. 02

    Consistent accessibility behavior (keyboard, screen reader) baked into components once, not re-implemented per consumer.

  3. 03

    Reasonable bundle-size impact per component so adopting the library doesn't bloat every consumer's bundle.

ARCHITECTURE

Now assign responsibilities to clear boundaries. Each part should have one reason to change and an explicit contract with the next part.

  1. 01

    A monorepo housing the component packages, a shared design-token package (colors, spacing, typography as data, not hardcoded per component), and a documentation/playground site built from the same source.

  2. 02

    Components built with composable, headless-first primitives where feasible, so behavior (accessibility, keyboard handling) is decoupled from visual styling and easier to theme.

  3. 03

    A visual regression and accessibility test suite run in CI against every component, gating releases.

  4. 04

    Semantic versioning with automated changelog generation and a documented deprecation policy for breaking changes.

DATA FLOW

Trace one important user action from input to rendered result. This exposes ownership, race conditions, retries, and stale-data paths.

  1. 01

    A component change is proposed, reviewed against the documented API and accessibility checklist, and merged with an accompanying changeset describing the semver impact.

  2. 02

    CI runs visual regression, unit, and accessibility tests, then publishes a new version and updates the docs site on merge.

  3. 03

    Consuming teams update their dependency on their own schedule, guided by the changelog and deprecation warnings surfaced ahead of breaking releases.

TRADE-OFFS

There is no perfect architecture. State what each choice optimizes, what it costs, and the signal that would make you revisit it.

  1. 01

    Headless/composable primitives maximize flexibility for consumers but require more integration work per consumer than a fully pre-styled, opinionated component; the right balance depends on how visually different consumers actually need to be.

  2. 02

    Strict semver discipline builds trust but slows down how quickly the library can evolve; a clear deprecation window is usually a better tradeoff than either extreme.

  3. 03

    A single monorepo for all components simplifies cross-component consistency but couples release cadence; independently versioned packages decouple releases at the cost of more coordination overhead for shared tokens.

SCALING

Scale the measured bottleneck rather than every box. Frontend scaling includes payload size, main-thread time, rendering work, cacheability, and release safety.

  1. 01

    Publish components as independently importable modules (not one giant bundle) so consumers only pay for what they use via tree-shaking.

  2. 02

    Automate visual regression testing so reviewing dozens of components' worth of changes doesn't require exhaustive manual QA on every release.

  3. 03

    Provide codemods for breaking API changes so large consumers can adopt them mechanically instead of manually rewriting every call site.

COMMON PITFALLS

Interviewers often probe these failure modes. Name them before being prompted and explain the guardrail you would add.

  1. 01

    Baking a specific product's visual identity directly into 'shared' components instead of exposing it through theming/tokens, making the library unusable for other consumers.

  2. 02

    Treating accessibility as a per-consumer concern instead of solving it once in the shared components, leading to inconsistent (and often broken) behavior downstream.

  3. 03

    Shipping breaking changes without a deprecation window or migration tooling, which erodes trust and causes teams to pin to old versions indefinitely.

Your closing summary

Restate the critical user flow, the most important quality target, the architecture boundary that protects it, and the trade-off you accepted. Then name the first metric you would watch after launch.

Back to all cases →