So today I spent a few hours on stupid things but hey, at least I've learned some new tricks about custom elements, aka Web Components. Let me share them with you.
Don't forget to define the custom element
If you have a class extending HTMLElement
and you try to instantiate it without defining the custom element beforehand, it will not work.
class MyElement extends HTMLElement {
...
}
const el = new MyElement();
// => Uncaught (in promise) TypeError: Illegal constructor
// Do this instead
customElements.define('my-element', MyElement );
const el = new MyElement();
// :-) great!
Content within slots is rendered using light dom
While checking a routing library, I was surprised that even though it was using shadow dom, everything displayed inside the router was using global styles (eg: Bootstrap).
I was really surprised! Isn't the whole point of shadow dom to encapsulate the styles? It seems it's more complex than that and this article explains it very well.
Is there a difference in appending everything to a slot in a shadow dom or just appending nodes as usual without a shadow dom? I'm not sure!
class MyElement extends HTMLElement {
constructor() {
super();
const shadow = this.attachShadow({ mode: 'open' });
const template = document.createElement('template');
template.innerHTML = '<slot></slot>';
const contentTemplate= document.createElement('template');
contentTemplate.innerHTML =
'This is a <button class="btn btn-primary">custom</button> element!';
shadow.appendChild(template.content.cloneNode(true));
this.appendChild(contentTemplate.content.cloneNode(true));
}
}
whenDefined is really great
You don't always know when something is loaded or defined in Javascript. So let's say you load a lib somewhere but configure it somewhere else, it could be tricky to apply configuration because you don't always know if everything is loaded properly.
Custom elements solve this very nicely with the whenDefined
callback that allows to run init or configure global options. For example...
customElements.whenDefined('my-element').then(async () => {
MyElement.setOptions({
...
});
});
That's all for today :-)