Skip to content
WC Toolkit Angular Wrappers artwork

Angular Wrappers

Generate standalone, typed Angular wrappers for your custom elements

@wc-toolkit/angular-wrappers generates standalone Angular components from a Custom Elements Manifest (CEM). Each generated component uses the custom element’s tag as its selector and exposes typed Angular inputs and outputs, so Angular templates can check bindings against your web component API.

Install

Terminal window
npm install -D @wc-toolkit/angular-wrappers

Angular 16.1 or later is required.

Generate wrappers

Use the plugin that matches your manifest workflow.

With the WC Toolkit CEM Generator

Add the plugin to cem-generator.config.mjs and run cem generate:

import { angularWrappersGeneratorPlugin } from "@wc-toolkit/angular-wrappers";
export default {
plugins: [angularWrappersGeneratorPlugin({ outdir: "./src/app/wrappers" })],
};

With the CEM Analyzer

Add the plugin to custom-elements-manifest.config.mjs and run cem analyze:

import { angularWrappersAnalyzerPlugin } from "@wc-toolkit/angular-wrappers";
export default {
plugins: [angularWrappersAnalyzerPlugin({ outdir: "./src/app/wrappers" })],
};

Programmatically

For a custom build script, pass a manifest object directly to the generator:

import manifest from "./custom-elements.json" with { type: "json" };
import { generateAngularWrappers } from "@wc-toolkit/angular-wrappers";
generateAngularWrappers(manifest, { outdir: "./src/app/wrappers" });

Use generated components

The output directory contains one standalone component per custom element and an index.ts barrel file. Import the generated wrapper into the Angular component that uses it:

import { Component } from "@angular/core";
import { MyButton } from "./wrappers";
@Component({
selector: "app-root",
standalone: true,
imports: [MyButton],
template: `
<my-button
[variant]="variant"
[disabled]="isSaving"
(myClick)="onClick($event)"
>
Save
</my-button>
`,
})
export class AppComponent {
variant: "primary" | "secondary" = "primary";
isSaving = false;
onClick(event: CustomEvent<{ count: number }>) {
console.log(event.detail.count);
}
}

Generated wrappers use the custom element as their host, so projected content remains light DOM children. Inputs are typed from the element class and manifest documentation; boolean attributes are coerced with Angular’s booleanAttribute. Custom events become outputs with camel-cased names (my-click becomes myClick), and generated listeners are removed when the Angular component is destroyed.

Compile the generated TypeScript with your library build (for example, ng-packagr) or copy it into the consuming application.

Configuration

All options can be passed to either plugin or generateAngularWrappers().

OptionDefaultPurpose
outdir"./angular"Directory for generated files.
packageJsonPathprocess.cwd()/package.jsonPackage manifest used to resolve fallback module imports. Set this when generating outside the element package or in a monorepo.
modulePathCEM module path(className, tagName, cemModulePath?) => string to customize element module imports.
defaultExportfalseImport element classes as default exports.
stronglyTypedEventstrueGenerate event aliases with the custom element as the event target.
ssrSafefalseBrowser-gate event wiring and dynamically load custom element modules for Angular SSR.
attributeMapping{}Map HTML attributes to safe Angular input names, for example class to cssClass.
globalProps, globalEvents[]Add shared inputs or outputs to every generated wrapper.
componentNameFormatter—Customize generated class and file names.
exclude[]Skip components by class name.
descriptionSrc"description"Manifest field used for component documentation.
debugfalseEnable detailed generation logs.
failOnWarningsfalseTreat generation warnings as errors; recommended for CI.
skipfalseSkip generation, useful for conditional builds.

Reserved attribute names

Generation fails if an element has attributes named class, for, style, or children, because these conflict with HTML or Angular names. Map them to another input name:

angularWrappersAnalyzerPlugin({
attributeMapping: { class: "cssClass" },
});

Server-side rendering

Set ssrSafe: true to load custom element modules only in the browser and attach event listeners there. This avoids eagerly evaluating client-only custom element code during server rendering.

Limitations

  • Angular template checking only covers components imported into the Angular component. Raw custom element tags without generated wrappers still require CUSTOM_ELEMENTS_SCHEMA.
  • Generated types and documentation depend on the information available in the CEM; undocumented members are omitted.