Disclaimer: a custom element usually has a friendly wrapper called a “web component” built with tools like Lit.
<h1>Howdy</h1>
HTML tags are not hyphenated; custom elements are. A tag like <yt-touch-feedback-shape>
is rendered by the browser as a custom element that can be defined with a JavaScript class and then registered for use on a webpage.
Let’s make our own by extending HTMLElement
. Then we can create a ShadowRoot
which is an encapsulated piece of DOM. Kind of like <video>
— it has play and pause buttons but those are not available as children of the video node. See the inheritance tree,
class PeterPan extends HTMLElement {
constructor() {
super()
}
/* connectedCallback() is called once the element is connected to the DOM.
In here we can procedurally build the custom element starting from
a special root node called a ShadowRoot.
*/
connectedCallback() {
const shadow = this.attachShadow({ mode: "open" });
const span = document.createElement("span");
const hat = this.getAttribute("hat");
span.textContent = `Help, Peter! I'm stuck in the window!`;
console.log(`Have you seen my ${hat}?`);
shadow.appendChild(span);
}
}
customElements.define("peter-pan", MyElement);
Then in our html we can write out the tag someplace in the body of our document —
<peter-pan hat="tyrolean"></peter-pan>
Writing Everything Twice can be fun but best practices tell us to Don’t Repeat Yourself. Enter templates and slots.
<template id="my-template">
A hat is a hat. I have <slot name="num">4</slot> hats.
</template>
Now if we update our PeterPan
custom element to use the template,
let tmpl = document.getElementById("my-template"); // Get the template
shadow.appendChild(tmpl.content.cloneNode(true)); // Clone the contents of the template node
Now, we can replace the num
slot with a <span>24</span>
.
<peter-pan>
<span slot="num">24</span>
</peter-pan>
Which will give us,
<peter-pan>
A hat is a hat. I have <span slot="num">24</span> hats.
</peter-pan>