Generating React, Angular, and Vue Wrappers from One StencilJS Component Library
A practical guide to adding React, Angular, and Vue output targets in stencil.config.ts, how the generated proxies map props and events, and what breaks when you ship one library to many frameworks.
16 Jul 2026, 14:06 UTC

If you maintain a Stencil library of custom elements and need to consume it inside React, Angular, and Vue applications, you do not have to rewrite the components three times. Add react, angular, and vue entries to outputTargets in stencil.config.ts. Stencil compiles your components once into standard custom elements and emits typed proxy files that forward props, attributes, events, and slots to those elements.
Worked configuration
Keep the custom-element bundle and point each framework target at a generated file. Run the build from the Stencil library project root.
// stencil.config.ts
import { Config } from '@stencil/core';
export const config: Config = {
namespace: 'my-library',
outputTargets: [
{ type: 'dist' },
{
type: 'react',
proxiesFile: '../react/src/components.ts',
},
{
type: 'angular',
directivesProxyFile: '../angular/src/directives/proxies.ts',
},
{
type: 'vue',
proxiesFile: '../vue/src/components.ts',
},
],
};
Run npm run build (or npx stencil build) in the library root. No elevated permissions are required. After the build, confirm the three configured paths exist and that each generated file typechecks in its host project. Exact option names and defaults vary across Stencil major versions, so verify them against the installed version before relying on this shape.
How the proxies work
Stencil still compiles components to standard custom elements. The generated wrappers are ordinary framework code. A React proxy maps React props to element attributes or properties and re-emits DOM events as React event handlers. An Angular directive proxy registers the custom element as a known Angular component and maps inputs and outputs. A Vue proxy does the same for Vue props and emits, and it also handles v-model through the component-models package.
Because the wrappers are generated at build time, they are build artifacts. Do not edit them by hand; the next build overwrites them. Commit the Stencil source and config, not the generated framework files.
Single library versus per-framework packages
Shipping one web-component library with generated wrappers is not the only option. The table below summarizes the main engineering tradeoffs.
| Aspect | Single library + generated wrappers | Per-framework packages |
|---|---|---|
| Source of truth | One Stencil component set | Separate implementations or duplicated logic |
| Build artifacts | Proxy files regenerated on every build | Framework-specific packages built independently |
| Runtime dependency | React/Angular/Vue wrapper packages plus the custom-elements runtime | Only the framework runtime |
| Prop and event mapping | Automatic, typed, but must be regenerated after renames | Manual or duplicated per framework |
| Server rendering | Requires an explicit hydration strategy | Can use native framework SSR |
| Version alignment | Wrapper versions must match the Stencil library | Independent versioning per package |
Common mistakes and limits
- Editing generated proxy files. They are overwritten on the next build. Change the Stencil component and rebuild instead.
- Forgetting
defineCustomElements(). The wrappers do not register the custom elements. CalldefineCustomElements()in the application entry point (for example,main.tsorindex.js) so the elements are defined in the browser. - Assuming server rendering works out of the box. The custom-elements runtime is browser-oriented. Add a hydration strategy or render fallbacks before expecting SSR to behave like native framework components.
- Version drift. The React, Angular, and Vue packages are runtime dependencies. Mismatched versions between the Stencil library and the wrappers can cause missing or duplicated custom-element definitions.
- Renaming without rebuilding. Proxies are generated at build time. A renamed
@Propor@Eventrequires a rebuild and republish before the wrapper types reflect it.
Verification checklist
- Run the build and confirm the configured
proxiesFileanddirectivesProxyFilepaths are written and typecheck cleanly. - Import one generated wrapper into a minimal app for each framework. Verify that a prop, a custom event, and a slot behave like the native custom element.
- Rename a
@Propor@Eventin the Stencil component, rebuild, and confirm the generated wrapper types change accordingly. - Check the published package exports so each framework entry point resolves to the generated wrapper and the custom-elements bundle.
If a prop does not update or an event never fires, first check whether the wrapper was regenerated after the component change, then confirm defineCustomElements() runs in the consuming app, and finally compare the wrapper package version against the Stencil library version.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.