In the mid-1990s, long before the era of React and Angular, the seeds of componentized web UI were already being sown:
Microsoft’s “HTML Components” (HTCs) for Internet Explorer 4 (circa 1997) let you define reusable widgets in HTML, CSS, and JScript—living in
.htc
files and attached viabehavior:url(...)
. It was clunky, Windows-only, and plagued by cross-browser woes, but it proved the allure of packaged, reusable UI.
A few years later, Mozilla experimented with XBL (XML Binding Language) in Firefox 1.0 (2004). XBL let you declare new tags in XML, bind them to scripts and styles, and even override native widget behavior. Again, powerful—but complex, tied to the browser’s internals, and ultimately never standardized.
2011: Alex Russell’s Amsterdam Lightbulb Moment
At a crisp autumn conference in Amsterdam (often cited as late 2011), Google’s Alex Russell took the stage with a simple yet radical vision:
“What if we let authors define their own elements—HTML tags—with their own markup, styles, and behavior—natively in the browser?”
He sketched out four core primitives—Custom Elements, Shadow DOM, HTML Imports, and HTML Templates—that together would let web developers build encapsulated, reusable widgets without frameworks.
Browser Vendors Eat Their Own Dog Food
Fast-forward a few years, and these primitives were battle-tested inside the browsers themselves:
-
<select>
controls, with their dropdowns, keyboard handling, and focus rings, were refactored atop Shadow DOM to isolate complex internals. -
<video>
and<audio>
players, complete with controls, timelines, and captions, too—each browser shipping its own custom element sealed behind a protective Shadow Root. - Even form controls like
<input type="date">
and<progress>
leverage these same technologies under the hood.
By using component tech for their standard tags, browser vendors proved the performance, security, and maintainability benefits of encapsulation—and gave developers a live demo of Shadow DOM and Custom Elements in action.
And then the Browser vendors opened up the technology to us mortal developers. But not as you might know it.
EVERY <tag-name>
Is a Custom Element
Here’s the kicker: any valid HTML tag name containing a dash—for example <user-card>
, <app-nav>
, or even <weather-widget>
—is already a fully-fledged HTMLElement
:
- It parses, lays out, and styles just like
<div>
or<span>
. - It participates in the CSS cascade and can be targeted with selectors:
weather-widget { display: block; border: 1px solid #ccc; }
- It reserves the namespace so you’ll never conflict with a future standard tag.
That means you can immediately start structuring your markup semantically—replacing generic <div>
s with <site-header>
, <product-list>
, <chat-bubble>
, etc.—and style them purely with CSS.
NO!! JavaScript required to get the semantic and style benefits of “components.”
The Takeaway
From Microsoft HTCs to Mozilla XBL, from Alex Russell’s talk in Amsterdam to the browser-built <select>
and <video>
controls, the Web Components idea has been decades in the making.
Today, ANY custom tag name is a native HTMLElement
. You don’t need JavaScript to reap immediate gains in readability, maintainability, and style encapsulation—just start writing HTML and CSS with meaningful tag names.
The era of “div-soup” is finally over!
Well... has been for nearly a decade now.
And you might not want to pay for a "Web Components" course, that starts with a JavaScript example.
Also read: https://dev.to/dannyengelman/not-a-div-insidein-sightsite-18lj
Top comments (2)
This is such a great trick that doesn't get talked about enough. Changing a
div.margin-top
into avertical-spacer
is so much easier to read.And as an added benefit: Framework authors (hi, that's me) can introduce components in terms of external formatting independent of any behaviour, and coponent authors (hi, that's also me) can write custom elements to describe their behaviour, so that website authors (you guessed it), can combine the two with relatively little to no coupling.
This is specially cool for components that are 95% presentation but benefit from smaller behaviour changes for improved quality of life, like a header bar that might detect if the page is scrolled to the top.
Lets not call it a trick.
This is what browser do since they implemented Custom Elements.
There are multiple types of Custom Elements
undefined Custom Elements
<template shadowrootmode="open">
defined Custom Elements (requiring JavaScript)
Defined Named Custom Elements (the class is named)
class MyComponent extends HTMLElement{}
customElements.define("my-component", class extends MyComponent)
defined Unnamed Custom Elements (Unnamed class)
customElements.define("my-component",class extends HTMLElement{})
The clue is undefined Custom Elements can be upgraded (with JavaScript) to defined Custom Elements
Note that you can use any tag
<foo>
and style it with CSS. But that will always be aHTMLUnknownElement
it can not be upgraded like Custom Elements (with a - dash) can.