Introduction to Web Components
A brief introduction to the set of specifications called Web Components. We'll introduce you to concepts such as Shadow DOM, HTML templates, Custom Elements v1 and uncover typical use cases for developing Web Components.
In the nineties web development was egalitarian. HTML provided a syntax anyone could learn. A <p>
element displays a paragraph. An <img>
element displays an image, provided a src
attribute has a valid address for an image file. The HTML standard evolved over time, however the elements used in development in the nineties still work today.
What it takes to develop a website has dramatically changed over the years. Web development became even more sophisticated when corporations discovered an advantage web had over native: anyone can access software in a web browser and updates can be pushed server-side, without the need for the end-user to trigger a software update. JavaScript frameworks like React, Angular, and Vue filled in the gaps of the ECMAScript standard, giving web engineers sophisticated tools and patterns for coding feature-rich web applications. React, in particular, popularized the notion of classes with React.createClass
before ECMAScript delivered the standards-based class
with the ES2015 standard, otherwise known as ES6. While JavaScript frameworks created fragmentation with incompatible component models, JavaScript frameworks have one thing in common. React, Angular, and Vue all feature a discrete unit of functionality that encapsulates template, styling, and user interface behaviors called the "component".
Framework-based UI components solved a distinct problem in web development by providing a component model, but the web platform lagged behind. There was no way to create a custom HTML element. Web developers could only use the HTML elements provided by the HTML standard, and extending the prototype of a native HTML element was considered a bad practice. In web application templates, each of the frameworks allow framework components to be declared alongside HTML elements, although components from two different frameworks don't necessarily work together in the same template. The opinionated implementation of one framework component clashes with another. Rendering multiple framework components in a single architecture can become extremely brittle. It's amazing how much JavaScript frameworks provide out of-the-box, but they don't really play nice together.
The fragmentation caused by JavaScript frameworks pose a problem at scale in corporations. Maintaining a consistent look and feel across a portfolio of many web applications is seemingly impossible when several engineering teams develop with different JavaScript frameworks. The same UI component could be duplicated many times over as the component is developed specifically for each framework. Pushing out changes to design and UX behavior becomes a herculean task, dealing the dependency chain of each JavaScript framework along the way.
Supporting accessible behaviors in framework-based UI components is challenging because when developing custom UI you essentially have to reinvent the wheel. Engineers may create a button component with a framework, but mistakingly use the template of a <div>
, losing the accessibility behaviors of <button>
in the process. The engineer would have to implement event listeners on keydown to listen for the spacebar and return keys being pressed, adding to the complexity of the codebase they maintain. Custom elements can extend from native HTML elements, retaining the accessibility behaviors of the element they extend from. This isn't to say Web Components aren't without challenges when it comes to accessibility. Shadow DOM can block screen readers from analyzing WAI-ARIA attributes when ids are deeply nested across Shadow boundaries, so developer intervention maybe needed to coax screen readers to obtain the desired results for accessibility.
Other problems with framework-based UI component development occur over time. Breaking changes in major versions of frameworks can cause churn. As frameworks optimize over time, breaking changes to syntax or different ways of working force engineers to relearn how UI components are developed. Rarely nowadays would you see React.createClass
in a modern React application, instead engineers would use the class-based React.Component
or a functional implementation with React hooks. A standards-based Web Component has a longer lifespan than framework components. Like those HTML elements <p>
and <img>
, Web Components are part of the HTML specification. A custom element registered with the CustomElementRegistry
will work in browsers for several years to come.
xxxxxxxxxx
export class CardComponent extends HTMLElement {
constructor() {
super();
const shadowRoot = this.attachShadow({ mode: 'open' });
const template = document.createElement('template');
template.innerHTML = `
<style>
:host {
display: block;
background: white;
border-radius: 12px;
border: 4px solid black;
overflow: hidden;
max-width: 320px;
min-height: 120px;
}
</style>
<header>
<slot name="header"></slot>
</header>
<section>
<slot name="body"></slot>
</section>
<footer>
<slot name="footer"></slot>
</footer>
`;
shadowRoot.appendChild(template.content.cloneNode(true));
}
}
customElements.define('in-card', CardComponent);
Web Components are interoperable, meaning custom elements can be used in the context JavaScript frameworks like any other HTML element.
xxxxxxxxxx
export {CardComponent} from "./custom-element";
​
export const App = () => {
return (
<div>
<in-card></in-card>
</div>
)
}
​
ReactDOM.render(<App />, document.querySelector("#root"));
Custom elements created with the Web Components standard can retain the accessibility behaviors of the HTML elements they extend. A customized built-in element that extends from HTMLButtonElement
includes all the traits of a typical HTML <button>
element. When the user presses Enter or Space, the button is activated without any custom logic. This isn't to say sometimes accessibility behaviors are not necessary to implement in autonomous custom elements or form-associated custom elements.
xxxxxxxxxx
export class ButtonComponent extends HTMLButtonElement {
constructor() {
super();
}
connectedCallback() {
this.addEventListener('click', this.onClick);
}
onClick() {
this.dispatchEvent(new CustomEvent('buttonClicked'));
}
}
​
customElements.define('in-button', ButtonComponent, {extends: 'button'});
Somehow we find ourselves at a place where web development is no longer egalitarian. The learning curve for web development is absurd for anyone who just wants to put a custom element on a page. Not only does someone have to learn the component model for a particular JavaScript framework, but how to test, maintain, and deploy complex framework code. Then another framework becomes popular and engineers have to relearn everything. We call this JavaScript fatigue. Part of the problem is the fragmentation, but in my opinion, it's mostly a problem with education. If people new to web development are skipping web standards in favor of learning frameworks, they are adding complexity, without learning about how things work. HTML elements are the most primitive Object we have to deal with in web development. Anyone can start developing UI with Web Components right in the browser.

While it's not practical to develop custom elements this way in the browser, the example above is useful to demonstrate that Web Components require zero dependencies to work.
What are Web Components?#
Front end web development usually requires handling templates, styling, and logic that defines the behavior of discrete functional units, commonly referred to as UI components. Web Components are a set of browser specifications that provides encapsulation and organization for user-interface logic in a standard component model. The term "custom elements" is often used interchangeably with "web components", although custom elements are just one of the specifications that comprise Web Components.
Web Components is a marketing term that refers to several browser standards maintained by the Web Hypertext Application Technology Working Group (WHATWG) and the World Wide Web Consortium (W3C) in the HTML Living Standard and DOM Standard, documents that establish the ongoing state of Hyper Text Markup Language (HTML) and Document Object Model (DOM). WHATWG is comprised of web engineers from Apple, Google, Microsoft, Mozilla, Opera and the broader web development community. In 2019, W3C and WHATWG agreed to work together to maintain the HTML standard as a living document that constantly evolves over time.
In contrast to open source JavaScript frameworks that are maintained by corporate teams or the broader community, Web Components are developed through a rigorous standardization process. Once a particular Web Component standard is finalized, browser vendors prioritize and implement the specification. As of January 2020, all major web browsers including Apple Safari, Google Chrome, Microsoft Edge, Mozilla Firefox, and Opera implemented the major feature of Custom Elements v1 specification: autonomous custom elements. Other specifications under the Web Components umbrella, such as Shadow DOM and HTML templates, have been part of the HTML standard for quite some time, while some like Declarative Shadow DOM or Constructable Stylesheets have yet to be included in all major web browsers. As HTML is a living document, support changes over time and any feature that lacks support in some browsers can be polyfilled. We'll look into this in more detail later. For now, let's define the various specifications that make up Web Components.
Custom elements#
The cornerstone of the Web Components featureset, custom elements allow new HTML tags to be defined in a web browser. Custom Elements v1 is the stable implementation of the custom elements specification. This standard allows you to define a new HTML element and the HTML element's JavaScript API. Other specifications like ElementInternals
extend the functionality of custom elements beyond the set of specifications known as Custom Elements v1. Custom elements allow you to observe changes to element attributes and manage content and styling for the new element's template. Custom elements behave like any other HTML element, with some syntactical sugar that promotes standardization across any custom element behavior.
There are three different types of custom elements: autonomous custom elements, customized built-in elements, and form-associated custom elements.
Autonomous custom elements#
Autonomous custom elements allow you to define customized functionality for a new HTML element. Autonomous custom elements extend from the HTMLElement
class. The most compatible custom element type, autonomous custom elements are available in all evergreen browsers. This specification is what people are typically referring to when describing Web Components or Custom Elements v1.
Customized built-in elements#
Customized built-in elements extend from known HTML elements, retaining the behaviors of those elements. Customized built-in elements behave differently than autonomous custom elements, although this specification retains many of the features of autonomous custom elements. Customized built-in elements can be used in several evergreen browsers, except Apple Safari which requires a polyfill.
Form-associated custom elements#
HTMLFormElement
cannot access form controls like HTMLInputElement
and HTMLSelectElement
that are within a custom element's Shadow DOM tree. This means form validation is precarious at best. Form-associated custom elements provide an extended API from autonomous custom elements that gives you hooks into form validation. This means you can still encapsulate a form control's template, while exposing the validity of the control to the parent HTMLFormElement
. Form-associated custom elements open the door for the creation of truly customized user experiences that participate in HTML forms. Instead of merely relying on traditional form elements, it's now possible to make your own.
This lesson preview is part of the Fullstack Web Components course and can be unlocked immediately with a \newline Pro subscription or a single-time purchase. Already have access to this course? Log in here.
Get unlimited access to Fullstack Web Components, plus 70+ \newline books, guides and courses with the \newline Pro subscription.
