Custom elements (web components) — register dynamically in the DOM with custom-element-register package
I have been working quite a bit with custom elements, more specifically with Angular’s take on them with Angular Elements but that is neither here nor there for the purposes of this post.
I couldn’t find a well packaged dynamic solution to injecting script and custom elements into the DOM at runtime, yet the implementation is pretty straight forward (maybe that’s why).
Why would I want to do this?
In a world of SPAs (single page applications) it makes sense to only inject scripts as we need them. Especially if your custom element is serving as a gateway to expose much deeper layers of your stack. You don’t want the performance overhead if you don’t need it!
I’ve created a little script which does two things:
- Dynamically creates a
<script>
tag in the DOM body to inject a JavaScript file which defines a custom element. - Dynamically injects a custom element tag e.g.
<my-app />
into a container (HTML element) of your choice.
As I already mentioned, the implementation is pretty basic:
How can I use it ?
To utilise this in your project, follow these simple steps:
- Add the npm dependency to your project:
npm i custom-element-register --save
- Import
RegisterCustomElement
script:import { RegisterCustomElement } from 'custom-element-register';
- Call
RegisterCustomElement()
script when you want to load the custom element dynamically with the following properties:
container
: HTML element your custom element tag should be injected into name
: a unique name which must match your custom element definition src
: path to your JS file serving your custom element
How would that work in a Angular component?
In an Angular component, it would be pretty much as mentioned above but I thought I would share an additional hook which works quite well to inject a custom element without adding any additional HTML tags to your component.
I know that DOM manipulation is naughty but I am taking this as an exception given my use-case.
Import some additional dependencies from /core:
import { ElementRef, AfterViewInit } from '@angular/core';
Implement the AfterViewInit lifecycle hook on your class definition:
export class SomeComponent implements AfterViewInit {
Create a reference to el which will be a pointer towards our component element:
constructor(private el: ElementRef) {
Now you can use RegisterCustomElement
in AfterViewInit to do the magic! The thing to note here is the reference to nativeElement.
ngAfterViewInit() {
RegisterCustomElement(this.el.nativeElement, 'my-app', '/my-app/element.js');
}
Finally, here’s the Github if you are interested:
Thank you for taking the time to read my article.