skip to content

For a component library serving teams on three UI frameworks, how do thin wrappers over an agnostic core, custom elements and shared behaviour logic compare?

level: middleimportance: must knowfreq 50%

answer

  1. what is written once vs per framework
  2. core plus thin idiomatic wrapper
  3. one element that every framework renders
  4. behaviour defined once, rendering per framework
  5. none of them reaches native mobile

basics

~20 s

Thin wrappers put everything framework-free in a core and give each framework an idiomatic shell; custom elements ship one implementation any framework renders; shared behaviour logic writes interaction rules once while each framework renders its own markup.

solid answer

~40 s

All three answer "what do we write once, and what per framework?" **Thin wrappers over an agnostic core** keep styles, markup structure and behaviour in the core and give each framework a small idiomatic shell: consumers get native-feeling components, and the library pays for N wrappers. **Standards-based custom elements** ship one implementation that any framework — and pages with no framework — can render; the cost is uneven framework integration for rich data, events, forms and server rendering, which is why teams often add thin wrappers on top. **Shared behaviour logic**, often a state machine, writes the hard interaction rules once while each framework renders its own markup: idiomatic output and natural server rendering, but more per-framework code. None of them delivers to native mobile apps, which share tokens and specs instead.

go deeper

for a junior

Know that a component written for one UI framework does not run in another, and name the three ways a library bridges that gap.

for a middle

Explain for each strategy what is written once and what per framework, and the main cost each one pays: wrapper count, integration friction, or per-framework rendering.

for a senior

Map a real estate to a choice: which surfaces have no framework, which render on the server, which frameworks are leaving, and how that combines strategies rather than picking one.

for a principal

Frame the choice as a long-term cost curve: per-framework layers multiply release and support effort, while a neutral core trades consumer ergonomics for longevity across framework churn.

## The problem: one design, several frameworks A **UI framework** has its own component model: how inputs arrive, how events leave, how the component re-renders. A component written for one framework cannot simply be dropped into another. Picture a multiplayer game's companion app whose web estate grew by acquisition: the clan portal is on framework A, the match-stats dashboard on framework B, the seasonal esports event site on framework C, and the store pages are rendered on the server with no framework at all. One design system has to serve all of them. Every strategy is an answer to the same question: **what is written once, and what is written per framework?** ## Strategy 1: an agnostic core with thin wrappers The **core** holds everything not tied to a framework: styles built on design tokens, the markup structure and its styling hooks, and plain behaviour functions. Each framework gets a **thin wrapper** that renders the core's structure in that framework's idiom, maps its inputs and events, and adds nothing else. - Consumers get components that feel native to their framework: its input conventions, its event conventions, its type checking. - The library maintains N wrappers, and each is a place where behaviour, defaults or styling can creep in and drift. - Pages with no framework need something extra — a plain-script version or one of the other strategies. ## Strategy 2: standards-based custom elements The web platform's **custom-element** standard lets a library define its own elements. Because frameworks render elements, any framework — and any server-rendered page — can use them without a framework-specific build. - One implementation to build, test and fix; it reaches the no-framework store pages; it outlives framework churn. - Frameworks integrate unevenly: handing over rich data rather than strings, listening for the component's events, taking part in forms and rendering on the server each need more or less glue depending on the framework. - Styling crosses an encapsulation boundary, so theming has to go through the hooks the element exposes. - Teams often add generated thin wrappers on top for idiomatic inputs and typing — which brings back part of strategy 1's cost. ## Strategy 3: shared behaviour logic The interaction behaviour — open and close rules, selection, keyboard handling, focus decisions — is written once as framework-free logic, commonly a **state machine**. Each framework writes a rendering layer that feeds user input to the logic and renders whatever state it reports. - The part that is hardest to get right is written and tested once. - Output is ordinary framework code, so server rendering and framework tooling work as usual. - Each framework still has markup, styling hooks and event binding to write — more per-framework code than a thin wrapper, and the rendering layers can drift. ## Comparing them | | Thin wrappers over a core | Custom elements | Shared behaviour logic | |---|---|---|---| | Written once | Styles, structure, plain behaviour | The whole component | Interaction rules | | Written per framework | A thin shell | Nothing, or optional wrappers | Rendering and event binding | | Feels idiomatic to consumers | Yes | Varies by framework | Yes | | Pages with no framework | Needs extra work | Yes | Needs a plain-script renderer | | Server rendering | As the framework does it | Needs extra care | As the framework does it | | Main risk | Wrapper drift | Integration friction | Rendering-layer drift | ## Choosing, and combining 1. **Count the frameworks and estimate their lifespan.** Two long-lived frameworks favour idiomatic output; a churning set favours custom elements. 2. **Check for pages with no framework.** The store pages alone can justify custom elements. 3. **Check server-rendering needs.** If most surfaces render on the server, idiomatic framework output is simpler. 4. **Check capacity.** Every per-framework layer is code to release, test, document and support. The strategies combine. A common shape is custom elements as the core with generated thin wrappers per framework; another is a shared behaviour core with per-framework renderers. None of them reaches the companion app's native mobile apps: those rebuild components natively and share **tokens and specs**, not code.

  • Why do teams that deliver custom elements often add thin framework wrappers anyway?
    Because frameworks integrate with custom elements unevenly. A wrapper can map the framework's input conventions to the element's properties, turn the element's events into the framework's event style, add type definitions, and smooth form participation. Consumers then write idiomatic code while the behaviour still lives once, in the element. The cost is that the wrappers must be kept thin, ideally generated, or they drift.
  • Which of these strategies delivers components to the native mobile apps?
    None. All three are web delivery strategies. A native app draws its interface with the platform's toolkit, so it rebuilds components natively against the shared spec and consumes the same design tokens exported in its own format. Behaviour rules can still be shared as written acceptance scenarios, but not as running web code.
  • What changes if one of the three frameworks is being phased out?
    Supporting it with a full idiomatic layer becomes hard to justify. Teams usually freeze that layer to fixes only, or serve the leaving framework through custom elements so no new framework-specific code is written, and set an end-of-support date aligned with the migration. The core keeps evolving for the frameworks that stay.

saying these in an interview costs you the question

  • Custom elements work identically in every framework with no integration effort.
  • A thin wrapper should hold its own behaviour and defaults for its framework.
  • Shared behaviour logic means no framework has to write its own markup.
  • Supporting several frameworks means copying the whole library once per framework.
  • Any of these strategies also ships the components to native mobile apps.