Custom Elements or Web Components

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,

Custom Elements in Elm 2023-10-31 11.10.04.excalidraw.svg

The code

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>

What about DRY?

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>
Custom Elements or Web Components
Interactive graph
On this page
The code
What about DRY?