Creating Framework Agnostic Apps with Angular Elements

Share on facebook
Share on google
Share on twitter
Share on linkedin

Browsers are becoming more and more powerful. Browsers are now able to do what was previously only possible with native apps,  and web apps that take advantage of the modern browser capabilities go under the name Progressive Web Apps. This includes a browser specification that enables browsers to have functionality such as offline availability, hardware support, and Bluetooth. Also, new browser specifications are enabling what was previously only available for SPA frameworks to the browser natively using web components that are encapsulating functionality and styling with techniques such as shadow dom and creating web components using custom-elements.

What is custom-elements? Custom-elements is part of the web component standard and is custom HTML tags that encapsulate functionality and styling. It is the browser-native implementation of what Angular is doing with javascript rendered components, just running natively and framework agnostic in the browser!

Angular has created a library for converting components into custom elements. This enables us to write components using the Angular framework and run the component in non-Angular applications. That way you can mix different front-end frameworks, as it all gets compiled to custom-elements.

Let’s see how easy it is to convert an Angular component to a custom element.

Converting an Angular component to a custom-element using @angular/elements

We are gonna create a simple demo of an Angular app by creating a component and using it to create a custom-element like in my Github demo.

The first step is to create a new Angular CLI project:

ng new angular-elements-demo

We need to install Angular elements:

npm i --save @angular/elements

And install some polyfills for web component browser compatibility:

npm i --save @webcomponents/custom-elements

And add the following lines to polyfills.ts:

import '@webcomponents/custom-elements/src/native-shim';

import '@webcomponents/custom-elements/src/custom-elements';

 

Hereafter you create a new component, that will later become a custom-element.

ng g c hello

Make sure to set ViewEncapsulation to native since we are to be working with custom-elements.

In the HelloComponent‘s decorator:

encapsulation: ViewEncapsulation.Native

 

For making Angular elements outside of Angular you need to change a couple of things in the AppModule:

  1. The HelloComponent is the component we want to create a custom element from. To do this we need to add it to declarations and entryComponents because the component is being created programatically (not created in a template).
  2. We want to use our custom element as our bootstrapped component, so to do this we need to setup the ngDoBootstrap lifecycle hook. Also we need to ensure that AppComponent is removed from the declarations and bootstrap properties in the decorator of AppModule.
  3. In the ngDoBootstrap create a new custom-element using createCustomElement. Make sure to provide the injector.
  4. Define the custom element using define. Here you specify the custom-elements HTML tag and the custom element to create.

Now when the app runs it will run a custom-element. You can remove everything from index.html and only specify the custom element as:

<hello></hello>

And you should see the HelloComponent being rendered!

The benefit of this is that this custom-element can be rendered in any framework now, as long as the compiled javascript bundles are provided. It is possible to run this app inside a React app and also there might be some performance benefits because of how browsers optimize for running web components vs running a javascript framework.

Publication of custom-elements

Unfortunately the way to use a custom elements created with Angular Elements is to build the bundles with ng build --prod --output-hashing=none and concat all the js files into one. Currently this creates  a pretty big bundle size, especially for an App that just displays some text. For this reason, it might not be reasonable to use Angular Elements in production yet.

Angular v7 and the Ivy renderer should make the published bundle of custom-elements created with Angular Elements even smaller, making this more useful in production. Also as the custom-element standard gets implemented in more browsers polyfills might not be needed anymore.

Conclusion

We discussed the benefits of creating framework agnostic apps using Angular Elements and saw how easy it is to convert an Angular component to a custom-element. Still, the technology has some drawbacks in a big bundle size and the need for polyfills to ensure browser support for custom-elements.

Do you want to become an Angular architect? Check out Angular Architect Accelerator.

Related Posts and Comments

How to Set up a CI pipeline with Azure Pipelines and Nx

It goes without saying that having a CI pipeline for your Angular apps is a must. Setting one up for regular Angular apps is fairly straightforward but when you have an Nx monorepo there are certain other challenges that you have to overcome to successfully orchestrate a “build once, deploy many” pipeline. This post will

Read More »

How to Set Up Git Hooks in an Nx Repo

Git hooks can be used to automate tasks in your development workflow. The earlier a bug is discovered, the cheaper it is to fix (and the less impact it has). Therefore it can be helpful to run tasks such as linting, formatting, and tests when you are e.g. committing and pushing your code, so any

Read More »

The Stages of an Angular Architecture with Nx

Long gone are the times when the frontend was just a dumb static website. Frontend apps have gotten increasingly complex since the rise of single-page application frameworks like Angular. It comes with the price of increased complexity and the ever-changing frontend landscape requires you to have an architecture that allows you to scale and adapt

Read More »

The Best Way to Use Signals in Angular Apps

Since Angular 16, Angular now has experimental support for signals and there is a lot of confusion in the community about whether this is going to replace RxJS or how it should be used in an app in combination with RxJS. This blog post sheds some light on what I think is the best way

Read More »

High ROI Testing with Cypress Component Testing

Testing is one of the most struggled topics in Angular development and many developers are either giving up testing altogether or applying inefficient testing practices consuming all their precious time while giving few results in return. This blog post will change all this as we will cover how I overcame these struggles the hard way

Read More »