Day 24 — Angular Elements: Exporting to Web Components
📘 Day 24 — Angular Elements: Exporting to Web Components
Zero to Hero — Hands-on Angular Tutorial
Today you will learn:
- ✔️ What are Web Components (Custom Elements)?
- ✔️ Why use Angular Elements?
- ✔️ Installing
@angular/elements - ✔️ Converting an Angular Component to a Custom Element
- ✔️ Building a standalone JS script (for use in React, Vue, or WordPress)
Usually, Angular components only work inside Angular. Today, we break those walls. You will create a component that works anywhere (even in a plain .html file). 🧱
🟦 1. What are Angular Elements?
Angular Elements allows you to package your Angular component as a standard Web Component (<my-widget>).
Capabilities:
- Works in React, Vue, Svelte, or vanilla JS.
- Self-contained (encapsulates styles and logic).
- Can be lazy loaded by scripts.
Use Case: Embedding a complex “Calculator” or “Chat Widget” into a legacy CMS or a partner’s website.
🟩 2. Setup
Install the package:
ng add @angular/elements
🟧 3. Create the Component
Let’s build a simple “Like Button” that increments a counter.
like-button.component.ts:
import { Component, Input, Output, EventEmitter, ViewEncapsulation } from '@angular/core';
@Component({
selector: 'app-like-button',
standalone: true,
template: `
<button (click)="like()">
👍 {{ count }} Likes
</button>
`,
styles: [`
button { background: #007bff; color: white; padding: 10px; border: none; border-radius: 5px; cursor: pointer; }
`],
// Important: Use ShadowDom to prevent styles from bleeding out/in!
encapsulation: ViewEncapsulation.ShadowDom
})
export class LikeButtonComponent {
@Input() count = 0;
@Output() liked = new EventEmitter<number>();
like() {
this.count++;
this.liked.emit(this.count);
}
}
🟥 4. Register as a Custom Element
Modifying app.config.ts (or main.ts) to tell the browser about this new tag.
app.component.ts (or main.ts):
import { Component, Injector, OnInit } from '@angular/core';
import { createCustomElement } from '@angular/elements';
import { LikeButtonComponent } from './like-button/like-button.component';
@Component({ ... })
export class AppComponent implements OnInit {
constructor(private injector: Injector) {}
ngOnInit() {
// 1. Convert Angular Component to Custom Element Class
const Element = createCustomElement(LikeButtonComponent, { injector: this.injector });
// 2. Register it with the Browser (window.customElements)
customElements.define('my-like-button', Element);
}
}
Now, you can use it in index.html:
<!-- Outside of <app-root>! -->
<my-like-button count="10"></my-like-button>
<script>
const btn = document.querySelector('my-like-button');
btn.addEventListener('liked', (e) => console.log('New Count:', e.detail));
</script>
🟫 5. Building a Standalone Script file
If you want to give this file to a React developer, you need a single .js file.
-
Build the app:
ng build --output-hashing=none -
Concatenate the output files (polyfill, main, runtime) into one. You can use a simple script or just manually import them.
Usually, the output in
dist/contains:main.jspolyfills.jsstyles.css
-
Embed in external site:
<html> <head> <link rel="stylesheet" href="styles.css"> </head> <body> <h1>My WordPress Site</h1> <!-- The Angular Element --> <my-like-button count="99"></my-like-button> <!-- The Script --> <script src="polyfills.js"></script> <script src="main.js"></script> </body> </html>
🎉 End of Day 24 — What You Learned
Today you liberated your components:
- ✔️
@angular/elements: The bridge between Angular and the Web. - ✔️
createCustomElement(): The conversion magic. - ✔️
customElements.define(): Registering the tag with the browser. - ✔️ ShadowDOM: Protecting styles from external CSS.
🧪 Day 24 Challenge
Build a “Weather Widget” Element.
Requirements:
- Accepts an
@Input() city(string). - Fetches mock weather data for that city.
- displays temperature and an icon.
- Build the project.
- Create a blank
test.htmlfile on your Desktop. - Include the built JS files and
<weather-widget city="London"></weather-widget>intest.html. - Open
test.htmlin Chrome and verify it works!