The first time I read the Custom Elements spec I closed the tab immediately. It felt like ceremony for something that should be simple. Six months later I came back, and something clicked.
The key insight
A custom element is just a class. You register it, the browser instantiates it when it sees your tag, and connectedCallback fires when it lands in the DOM.
class ReadingTime extends HTMLElement {
connectedCallback() {
const words = this.closest('article')
?.textContent.split(/\s+/).length ?? 0;
this.textContent = ${Math.ceil(words / 200)} min read;
}
}
customElements.define('reading-time', ReadingTime);
That's it. Drop anywhere near an article and it self-populates.
Why this matters
The platform ships features you never reach for because you assume they aren't there yet.
Once you internalize that, a lot of framework code starts looking like work you're doing for the browser, not with it.