skip to content

Cross-Framework Delivery

Serving teams on several UI frameworks from one library: an agnostic core with thin wrappers, standards-based custom elements or shared behaviour logic. Asked when an org's stacks diverge.

part ofDesign systems & UX foundationsoverview, primer and where to startread it →
on this pageshow

questions

5

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.
open as a page

In a design system with web and native mobile apps, what do native apps share with the web component library, and what do they rebuild?

level: juniorimportance: should knowfreq 42%

basics

~20 s

Native apps share the design tokens, the component specs (anatomy, variants, states, behaviour, accessibility intent) and the naming, not the web code. Each platform rebuilds the components with its own UI toolkit, input model and accessibility services.

open as a page

A game companion app's design system ships thin wrappers for three UI frameworks, and months later the same item picker behaves differently in each; what went wrong, and how do you stop wrapper drift?

level: seniorimportance: should knowfreq 38%

basics

~20 s

Wrapper drift happens when hand-written wrappers gain their own options, defaults and behaviour. Stop it with one machine-readable component contract that generates or type-checks every wrapper, a shared conformance suite run against each, and lockstep releases.

open as a page

As design-system lead for a game companion app whose web teams use three UI frameworks, how do you decide whether to support all three, standardise on one, or deliver framework-neutrally?

level: principalimportance: should knowfreq 25%

basics

~20 s

Weigh each framework's share of product surface and lifespan against the multiplied cost of supporting it, and the cost of teams rebuilding components if you do not. Usually the answer is tiered support with explicit entry and exit criteria.

open as a page

In a multi-framework component library, why define a combobox's interaction behaviour once as a framework-agnostic state machine, and what must each framework adapter still own?

level: middleimportance: nice to knowfreq 30%

basics

~20 s

Interaction rules are the costliest part to get right, so a render-free state machine lets every framework share one tested implementation. Each adapter still renders markup, binds platform input to machine events, moves real focus and runs side effects.

open as a page