Home

Creating Web Components using Angular Elements

Intro

Creating custom elements (also called Web Components) with Angular is a relatively new feature of the framework. As cool as that feature is, at the time of this writing (v9) the created custom elements are not yet meant to be used outside of an Angular application.

But while we wait for the Angular Team to make this amazing feature fully compatible with React, Vue or any other JavaScript project, we can already hack together some fun examples.

In this post we are going to create a Chat Widget Web Component that can be used within other JavaScript frameworks, or even vanilla HTML/CSS/JS projects.

The final result will look something like this:

TensorFlow.js working
Vanilla JS project.
The widget shows up when adding `<app-chat> </app-chat>` to the HTML.

Caveats

Fair warning: There are quite a few hacks in this mini project. It is meant to be very much experimental, as the idea is not yet fully supported by the Angular framework. If you need some more serious Web Component development, take the following into consideration:

  • In case your web components are not going to be used only within your Angular Project, you may favor going with Stencil or Lit Element.
  • If you really want to do this with Angular, make an effort not to add an entire unscoped styling library (unlike this example: we are adding the entire Nebular)

Also worth noting that we are not using Shadow DOM here as Nebular’s styles would need rework in order to work with that.

The full code is available on GitHub

Create a new Angular application

ng new angular-chat-web-component

Add Nebular’s Chat component

  1. Add Nebular
ng add @nebular/theme
  1. Add Nebular’s chat component
ng generate component chat
chat.component.html
<nb-chat title="Drag & Drop chat" size="medium">
  <nb-chat-message
    *ngFor="let msg of messages"
    [type]="msg.type"
    [message]="msg.text"
    [reply]="msg.reply"
    [sender]="msg.user.name"
    [date]="msg.date"
    [files]="msg.files"
    [avatar]="msg.user.avatar"
  >
  </nb-chat-message>
  <nb-chat-form (send)="sendMessage($event)" [dropFiles]="true"></nb-chat-form>
</nb-chat>

Adjust AppModule

A few small things need to be adjusted in app.module.ts.

  • It should no longer bootstrap a root component.
  • Implement DoBootstrap and call register for your custom components.
  • Remove AppComponent altogether.
app.module.ts
imports [...]

@NgModule({
  declarations: [ChatComponent],
  imports: [
    ...
  ],
  providers: []
  // bootstrap: [AppComponent],})
export class AppModule implements DoBootstrap {
  constructor(private injector: Injector) {}

  ngDoBootstrap() {    this.registerCustomElement();  }  registerCustomElement() {    // Convert `ChatComponent` to a custom element.    const ChatElement = createCustomElement(ChatComponent, {      injector: this.injector    });    // Register the custom element with the browser.    customElements.define('app-chat', ChatElement);  }}

Building the web components

This project includes a special hacky script build-elements.js, adapted from FireShip.io. The script basically just concatenates the Angular build files into ES2015+ and ES5 JavaScript bundles.

We can then just import them in our HTML, like so:

demo/index.html
<!-- Only one of the bellow files will be loaded by the browser, according to its ES2015 support -->
<script src="es2015-chat.js" type="module"></script>
<script src="es5-chat.js" nomodule defer></script>

The demo file is already setup in the project. To build and run the demo:

npm run build:elements
npm run launch:demo

Your custom element files will be copied into ./demo and your browser will open ./demo/index.html.

TensorFlow.js working
Voyla! It works!

Closing thoughts

Web Components have the potential to greatly simplify things in the frontend space by allowing us to integrate JavaScript components from one framework into another.

At the time of this writing Angular Elements are not yet cross-framework, but we can already do some fun stuff if a bit of hacking is acceptable.

The full code is available on GitHub

More Resources

FireShip.io
Angular Architects
NgConf