What Are Web Components?
The problem: reuse without a framework
Section titled “The problem: reuse without a framework”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:
| Property | Meaning |
|---|---|
| Reusable | Works in any HTML context, with any framework or none |
| Encapsulated | Internal markup and styles are isolated from the page |
| Native | No transpilation, no virtual DOM, no runtime library required |
Framework components vs Web Components
Section titled “Framework components vs Web Components”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.
Browser support today
Section titled “Browser support today”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.
A custom element is just a class
Section titled “A custom element is just a class”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.