Web Components are a set of browser-native APIs for building reusable, encapsulated UI components. The bundle: custom elements (define new HTML tags), shadow DOM (style isolation), and HTML templates.
They've been around for over a decade. Adoption has been steady but not overwhelming — frameworks (React, Vue) dominate.
This page covers what Web Components are and when they make sense.
Define your own HTML tags:
class MyButton extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.shadowRoot.innerHTML = `
<button><slot></slot></button>
<style>
button { background: blue; color: white; }
</style>
`;
}
}
customElements.define('my-button', MyButton);
<my-button>Click me</my-button>
The browser knows about <my-button> after customElements.define.
Encapsulates internal structure and styles. Shadow DOM contents don't leak out; outside styles don't leak in.
The "open" mode allows JS to access the shadow root; "closed" hides it entirely. Open is more common.
The <template> element holds DOM that doesn't render until activated:
<template id="my-template">
<div>Reusable content</div>
</template>
Templates can be cloned and inserted; they're inert until used.
Inside shadow DOM, <slot> defines insertion points for content from outside:
<!-- Inside shadow DOM -->
<div class="card">
<slot name="header"></slot>
<slot></slot> <!-- default slot -->
</div>
<!-- Outside -->
<my-card>
<h2 slot="header">Title</h2>
<p>Body content</p>
</my-card>
A Web Component works in any framework or no framework. If you need a button used in React, Vue, and plain HTML, Web Components are the only standard solution.
Web Components are part of the platform. They'll work in 10 years. React, Vue may have moved on.
A design system shipping Web Components can be consumed by any team regardless of their framework choice. Adobe, Salesforce, Microsoft do this.
Shadow DOM provides genuine isolation. CSS conflicts between components disappear. Useful when integrating with unknown environments.
A widget you embed in others' websites: Web Component is robust to whatever the host page is doing.
If your whole app is React, React components work better than Web Components. Native integration; ecosystem; tooling.
React's hooks, Vue's composition API are more ergonomic than the raw Web Components APIs.
React/Vue have massive ecosystems. Web Components ecosystem exists but is smaller.
SSR with Web Components works but is awkward. Frameworks have first-class SSR support.
Use Web Components for cross-framework or design system pieces; use React components for app-specific UI.
Frameworks built on Web Components. Provide better DX while still producing standard Web Components.
For teams committing to Web Components as the primary technology, these reduce the boilerplate.
class MyButton extends HTMLElement {
static observedAttributes = ['variant'];
attributeChangedCallback(name, oldValue, newValue) {
if (name === 'variant') this.update();
}
update() {
// re-render based on variant
}
}
Lit and Stencil simplify this.
Web Components fire DOM events that any consumer can listen to:
this.dispatchEvent(new CustomEvent('selected', {
detail: { value: this.value },
bubbles: true,
composed: true // pierces shadow DOM boundaries
}));
Consumers listen with standard addEventListener. Framework-agnostic.
Web Components can participate in forms via the ElementInternals API. Modern; not in all browsers.
For most app development:
For specific cases: