Standing on the shoulders of giants
I learned as much as I could on Web Components development since 2016. And I am still learning.
Credit where credit is due!
I could not have gotten this far without the answers on StackOverflow, the discussions on GitHub and the blogs from early-adoptersยน.
ยน) Old blogs can refer to V0 Web Component technologies not available in the current V1 standard
5 lessons to make your Web Component code better
-
Most (early) examples showed all three Web Component technologies in one code example
- templates
- shadowDOM
- custom Elements API
Each can be used without the other:
๐ You can use templates for any block of inert HTML
๐ You can assign shadowDOM to regular HTML Elements
๐ You can create Custom Elements without templates or shadowDOM
๐ฆ 1. <template>
- creates inert HTML snippets, where previously you would have used:
<script type="application/html">...</script>
or
<div style="display:none">...</div>
Templates are parsed when you use
template.content.cloneNode(true)
If you use template content once, you can skip the
.cloneNode(true)
partDo not use a
<template>
just because most (early) blogs show:
let template = document.createElement("template");
template.innerHTML = ` CSS & HTML CONTENT `;
this.shadowRoot.innerHTML = template.innerHTML;
This is a very expensive way of writing:
this.shadowRoot.innerHTML = ` CSS & HTML CONTENT `;
-
My personal preference, when I do use/need Templates, is to keep
<template>s
in the<head>
of the document.- They load early
- My IDE does all syntax highlighting
- I use
id="UPPERCASE"
so they stand out, and the<my-element>
can have a generic statement:document.getElementById(this.nodeName)
to read the<template>
<template id="MY-ELEMENT"> <style> :host { ... } </style> <div><slot><slot></div> </template>
Use
this.localeName
for lowercase notationid="my-element"
Declarative shadowDOM
templates can create shadowDOM, without the need for JavaScript
<my-element>
<template shadowrootmode="open">
<!-- shadowDOM content -->
</template>
<!-- lightDOM content -->
</my-element>
๐ฆ 2. super()
-
super()
sets and returns thethis
scope.
constructor() {
super();
this.title = "Web Components 102";
}
can be written as:
constructor() {
super().title = "Web Components 102";
}
๐ฆ 3. always call super() first in constructor
- Now you understand
super()
, you may question the comment many copy from the MDN documentation and early blogs:
constructor() {
// Always call super first in constructor
super();
// Element functionality written in here
}
What they meant to say was:
constructor() {
// You can *not* reference 'this' *before* it is created by super();
// It is valid to use *any other* JavaScript *before* super()
const template = () => document.getElementById(this.nodeName);
super().append( template().content.cloneNode(true) );
}
โผ๏ธ Note: template()
is a function, it is called after super()
created the 'this' scope. So this.nodeName
works
๐ฆ 4. attachShadow
-
attachShadow
sets and returnsthis.shadowRoot
So there is no need to create your own property:
this.shadow = this.attachShadow({mode:"open"});
constructor(){
super();
this.attachShadow({mode:"open"});
this.shadowRoot.innerHTML = `...`;
}
can all be chained:
constructor(){
super() // sets AND returns 'this'
.attachShadow({mode:"open"}) // sets AND returns this.shadowRoot
.innerHTML = `...`;
}
- note:
attachShadow({mode:"closed"})
does not setthis.shadowRoot
; preventing users from accessing your components shadowRoot. You will hardly seeclosed
being used in the wild
๐ฆ 5. appendChild vs. append
IE11 did not have the
el.append(nodes)
method; maybe that is why so many developers stick toappendChild
-
el.appendChild(element)
- MDN appendChild documentationappends one
element
, and returns theelement
reference -
el.append(nodes)
- MDN append documentationappends all nodes (text nodes & elements), and returns nothing
append
does not parse HTML, like.innerHTML
and.insertAdjacentHTML
do -
When you do not need the appendChild return value; you can rewrite:
super(); const shadow = this.attachShadow({mode: 'open'}); this.div = document.createElement('div'); this.style = document.createElement('style'); shadow.appendChild(style); shadow.appendChild(div);
to:
super() .attachShadow({mode: 'open'}) .append( this.div = document.createElement('div') , this.style = document.createElement('style') );
๐ฆ Make that 6
๐ฆ Or 7
Thank your for reading:
Web-Components #102 - 5 more lessons after learning Web Components #101
Top comments (4)
Thank you for creating such a great resource!
I didn't know this ๐คฏ
This is an interesting approach I've not seen or considered before. What are your thoughts on declarative shadow DOM?
DSD is a hype until all those developers(*) who whined about it for years start using it now it is available:
source: web-components-usage-metrics.githu...
(*) most doing SSR/SSG for the first time in their lives, because they never learned about the SSR Internet-world pre-WWW in the early 90s (with technologies like Gopher) and the main reason the WWW got popular is because doing things front-end had way more possibilities.
This is so great! I am super excited to dig into more info about Web Components... I've been afraid to post any of my learnings on it because its so new that I don't want to lead anyone astray with my hacking through it
Although you've inspired me to give writing about my findings a try
The best way to learn is by explaining/teaching it to others.