← Retour au blog
Web ComponentsAngular ElementsMicro-frontendsInteropérabilitéPerformance

Web Components and Angular Elements: Pragmatic Interoperability at Last

Angular Elements encapsulates your Angular components as standard Web Components, providing a genuine solution for code reuse beyond framework boundaries. Unlike earlier approaches based on proprietary libraries, Web Components rely on stabilized platform APIs: Custom Elements, Shadow DOM, and HTML Templates. This standardization means your exported Angular component will work in React, Vue, vanilla applications, or even a micro-frontends system without cross-dependencies. It's particularly valuable when you inherit a fragmented codebase or when building a library intended for teams using different stacks.

When and Why to Adopt Angular Elements

Web Components shine in three well-defined contexts. First, distributed micro-frontends: you can develop, test, and deploy an Angular component independently, then consume it in a shell application written in Vue or even jQuery without sharing an Angular instance. Second, team composition: a backend-heavy team can maintain generic UI components (buttons, modals, datepickers) that a frontend team integrates without knowing Angular. Third, progressive evolution: migrating from a legacy Backbone application to Angular no longer requires a big bang—it becomes gradual adoption where some screens remain in Backbone while others become Angular Web Components.

The decision to use Angular Elements must account for packaging overhead. An Angular Elements Web Component includes the full Angular runtime, meaning a 150–200 KB minified bundle for a single component. If you import ten of them on the same page, you duplicate the runtime ten times, unless you employ advanced bundling strategies. For simple, autonomous components (a date picker, an authentication widget), this overhead is acceptable. For a complex table with shared state, a unified architecture is preferable.

Concrete Implementation: From Component to Custom Element

Start with a standard Angular component, free of complex external dependencies. Reactive forms, HTTP, and signals work perfectly within a Web Component. Install @angular/elements via npm, then declare your component as an entryComponent in your module (or directly as standalone if you're on Angular 14+). The key step is creating an NgCustomElement and registering it with the DOM via customElements.define(). Angular Elements automatically handles component lifecycle, dependency injection, and change detection.

Here's a minimal example. Suppose a CounterComponent that manages a counter with two buttons:

import { Component, Input, Output, EventEmitter } from '@angular/core';

@Component({
  selector: 'app-counter',
  template: `<button (click)="decrement()">−</button>
             <span>{{ count }}</span>
             <button (click)="increment()">+</button>`,
  standalone: true
})
export class CounterComponent {
  @Input() initialValue = 0;
  @Output() countChanged = new EventEmitter<number>();
  count = this.initialValue;
  
  increment() { this.count++; this.countChanged.emit(this.count); }
  decrement() { this.count--; this.countChanged.emit(this.count); }
}

To export this component as a Web Component, create an entry file (for example, main.web-component.ts):

import { createCustomElement } from '@angular/elements';
import { createApplication } from '@angular/platform-browser';
import { CounterComponent } from './counter.component';

(async () => {
  const app = await createApplication({ providers: [] });
  const counterElement = createCustomElement(CounterComponent, { injector: app.injector });
  customElements.define('app-counter', counterElement);
})();

Then configure your build to produce a single, optimized bundle. The Angular CLI offers a dedicated schema (ng build --configuration production) that handles polyfill merging and encapsulated style extraction. You get a single JavaScript file, ready to inject into any HTML page or framework.

Interoperability and Common Pitfalls

The biggest challenge lies in state management and communication between Web Components. HTML attributes can only carry strings. To pass complex objects, you must use JavaScript properties (element.data = myObject) or custom events. Angular Elements automatically translates your @Input and @Output into DOM properties and events, but this translation can cause surprises if you expect synchronous reactivity.

A classic pitfall: developers assume modifying a Web Component property updates the render instantly. In reality, Angular Elements uses Angular's change detection mechanism, which is asynchronous. If you set element.count = 5 then immediately inspect the DOM, you may get the old value. The solution is to check your component's documentation, prefer events for critical updates, or let the Web Component manage its state internally via public methods.

Another gotcha: style management. Shadow DOM encapsulates CSS, meaning your global stylesheets don't cross the Web Component boundary. If you use Tailwind or Bootstrap, classes applied externally won't affect internal content. The most robust solution is to emit styles directly in the Angular component (via ViewEncapsulation.ShadowDom or inline stylesheets) or use CSS custom properties that the host can control.

Optimization and Deployment Strategies

To reduce bundle size, leverage AOT compilation and dead code elimination. Angular Elements supports tree-shaking, so unused dependencies are stripped. If you publish multiple Web Components, consider a central registry (for example, an HTML page that loads all elements) rather than isolated instances. This lets you share the Angular runtime and divide memory consumption by ten.

Deploying to a CDN is trivial: one JavaScript file, one or two stylesheets, and you're done. Modern browsers natively support Web Components without polyfill (except IE 11, which is dead). Versioning your Web Components is crucial: use suffixes in the element name (app-counter-v2) or semantic versioning in a data attribute, so consumers can coexist with multiple versions without conflict.

Pragmatic Conclusion

Angular Elements is not a silver bullet for every interoperability problem, but it's a solid, standardized tool for well-defined use cases. Use them to compose micro-frontends, distribute reusable components across teams, or enable progressive migration. Avoid heavy dependencies inside the component, aggressively test interoperability with your target consumers, and measure bundle size impact. The real strength of Web Components lies in their framework independence: once exported, your Angular code asks nothing but the browser. That neutrality is what makes it a lasting investment.

Développeur Angular & Mobile freelance — Strasbourg.

© 2026 Emilien Pons — Tous droits réservés.Conçu avec Angular, PrimeNG et ❤️