Yes, too many blogs do document.createElement("template")
where an .innerHTML
will do the same ... and with less code ... and faster.
Note, Templates are not tied to the Custom Elements API or shadowDOM.
Each of the 3 Web Components technologies can be used without the other.
Templates
Templates are great when you want to store re-usable content in the HTML Document, because it does not get parsed.
In the old days we would use a <div hidden>
and pray its contents did not affect the rest of the page.
Just like the old days you can read the Template.innerHTML and do whatever you want with the String value.
More modern approach is to clone the Template, just be aware that .content
property is required, and you get a Document-Fragment value in return.
<template id="MY-TEMPLATE">
<article>
...
</article>
</template>
document.getElementById("MY-TEMPLATE").content.cloneNode(true)
Templates & shadowDOM
When you have Custom Elements with shadowDOM, Templates are great to define that shadowDOM content.
Why so many developers want to do HTML-in-JS and CSS-in-JS I don't understand.
If you have an HTML document, store the content there, way easier to edit.
<template id="MY-ELEMENT">
<style>
/* style shadowDOM here */
</style>
<slot></slot>
</template>
All your MY-ELEMENT then needs to do is:
super() // or this when done in the connectedCallback
.attachShadow({mode: 'open'})
.append(document.getElementById(this.nodeName).content.cloneNode(true))
Performance
an innerHTML String with HTML content will get parsed for every usage.
A template is parsed once, so does save on CPU cycles, when you use the same template many many multiple times
Usage
My personal preference is to keep as much HTML (and CSS) inside <TEMPLATEs>
in HTML as possible. Only when I want my components not to be configurable I use static HTML in JS, with .innerHTML
, not .createElement("template")
for code brevity over (minor) performance gain
Only in SDWCs (Self Destructing Web Components) that need to load/execute ASAP I contain everything inside the Component:
customElements.define('my-head',class extends HTMLElement{
connectedCallback(){
// generate <HEAD> content, <SCRIPTS> and <STYLE> CSS-in-JS here
this.remove();
}
});