Skip to content

What Are Web Components?

Before Web Components, sharing a UI widget between projects meant either copying and pasting markup, or committing to a specific framework. A React button component cannot be dropped into a Vue app. A Svelte card cannot be reused in an Angular project.

Web Components solve this with three browser-native standards:

  • Custom Elements — define new HTML tags as ES classes
  • Shadow DOM — encapsulate the element’s DOM and CSS so styles cannot leak in or out
  • HTML Templates and Slots — declare reusable markup fragments and insertion points declaratively

The result is a component that is:

PropertyMeaning
ReusableWorks in any HTML context, with any framework or none
EncapsulatedInternal markup and styles are isolated from the page
NativeNo transpilation, no virtual DOM, no runtime library required

Framework components (React, Vue, Svelte) live entirely inside their framework’s runtime. The browser never sees a <MyButton> — it sees whatever the framework renders in its place.

<!-- React JSX — compiled away, never in the DOM -->
<MyButton variant="primary">Save</MyButton>
<!-- Web Component — a real DOM node the browser owns -->
<my-button variant="primary">Save</my-button>

Web Components are actual DOM nodes. You can query them with document.querySelector, listen to their events with addEventListener, and inspect them in DevTools — just like any built-in element.

All four major rendering engines support the complete Web Components v1 specification:

  • Chrome / Edge — full support since 2018
  • Firefox — full support since 2018
  • Safari — full support since Safari 10.1 (2017) for Custom Elements; Shadow DOM v1 since Safari 10 (2016)

The one exception is customized built-ins (extending existing elements like HTMLButtonElement). Safari does not support them and has stated it will not — autonomous custom elements (extending HTMLElement) are the portable choice. This is covered in the final lesson of this module.

At its core, a custom element is an ES class that extends HTMLElement and is registered with a tag name:

class MyGreeting extends HTMLElement {
connectedCallback() {
this.textContent = 'Hello from a custom element!';
}
}
customElements.define('my-greeting', MyGreeting);

After define, any <my-greeting> tag in the document — present or future — is automatically upgraded to an instance of MyGreeting.

Which of the following is a correct description of a custom element?
Which browser does NOT support customized built-in elements?
What is the main advantage of Web Components over framework components?
After calling customElements.define, what happens to existing matching tags in the document?