DEV Community

Cover image for How to use Web Components in HTMLTemplateElement in Angular
Patrick Sevat
Patrick Sevat

Posted on • Edited on

How to use Web Components in HTMLTemplateElement in Angular

TLDR

  1. Use [innerHTML] on the <template> tag
  2. Use DomSanitizer.bypassSecurityTrustHtml() to make sure your Custom Elements are not stripped from your provided HTML string

See code example at the end


Within the Rabobank Design System (based on Web Components) we sometimes come across with unusual specs. Our department relating to wholesale banking (large business customers) came up with the requirement of a select dropdown containing thousands of bank accounts.

We also envisaged different use cases than just thousands of bank accounts. Maybe thousands of checkboxes with labels and icons. To allow for future use cases we wanted to leverage the <template> component, also known as HTMLTemplateElement.

The cool thing about the <template> tag is that its contents are not actually rendered by the browser as long as they reside within <template>. This would give us the flexibility we need for our component.

Our components worked fine in plain HTML / JS but once we appended the components within our <template> tag to the DOM using Angular, it started double rendering! 😠

When inspecting the <template> element we also noticed that in Angular it did not yield a new DocumentFragment as it does in plain HTML...

This means the <template> tag was not recognized as such and because our Web Components used slots, those slots where rendered and then re-rendered upon appending to the DOM.

Unfortunately, searching Google for angular + template only yields results for ng-template, but after searching for Angular HTMLTemplateElement we got to this StackOverflow question, which point us to the [innerHTML] syntax.

After trying binding to the innerHTML property we noticed that the double rendering stopped, but the Web Components within the <template> tag were not rendering as they should, but with an example consisting of HTML5 elements (span, div, p...) it did render as expected.

There were two possible explanations:

  1. The Web Components were not registered correctly.
    • A quick inspection of the CustomElementRegistry showed that they were registered
  2. There is some sort of sanization in play that strips out "invalid" elements because of the usage of innerHTML

The sanitation turned out to be the culprit. By using the DomSanitizer we were able to mark our HTML as safe and get our code working as expected.

Code example

/* some-component.component.ts */
import { DomSanitizer } from '@angular/platform-browser';

@Component({
    selector: 'some-component',
    templateUrl: './some-component.component.html',
})
export class SomeComponent {
    constructor(private _sanitizer: DomSanitizer) {}

    templateHtml = this._sanitizer.bypassSecurityTrustHtml(`
        <webcomponent-bank-account>
            <span slot="label">John Doe</span>
            <span slot="balance">€ 100.000</span>
            <p slot="account-number">1234567890</p>
        </webcomponent-bank-account>
    `);
}
Enter fullscreen mode Exit fullscreen mode
<!-- some-component.component.html -->
<template #webComponentTemplate [innerHTML]="templateHtml">
</template>
Enter fullscreen mode Exit fullscreen mode

Top comments (4)

Collapse
 
ppbitb profile image
ppbitb • Edited

Googling this issue was impossible as noted. I was pointed to this post by a StackOverflow user.
Any idea or reference in the official docs why Angular is handling <template> differently?

Collapse
 
patricksevat profile image
Patrick Sevat

Hi @ppbitb ,

I have not dived into this further by going into the Angular source code and I haven't found any reference to this behavior in the documentation (so far). If you do come across any information please let me know and I'll update the article!

Collapse
 
ppbitb profile image
ppbitb

Thank you for your response.

I haven't found anything definitive, just sharing half-baked thoughts:

  • I dug through the angular sources, specifically the compiler package, but did not find anything. I don't have any compiler skills so that was a long shot. There is just this test that shows that template tag should be processed normally.
  • It looks like "proper" way to output a Web Component is to use an Angular Element. I have not tested this.
Collapse
 
rakiabensassi profile image
Rakia Ben Sassi

Thank you for sharing this nice article Patrick!