A complete guide to Web Components in 2025. Custom Elements, Shadow DOM, HTML Templates, Lit framework and integration with React, Vue and Svelte.
Introduction to Web Components¶
Web Components represent a set of web platform APIs that allow you to create new custom, reusable, encapsulated HTML tags to use in web pages and web apps. They work across modern browsers and can be used with any JavaScript library or framework.
The four main specifications that make up Web Components are: - Custom Elements - Define new HTML elements - Shadow DOM - Encapsulated DOM and styling - HTML Templates - Reusable markup patterns - ES Modules - Standard module system
Custom Elements¶
Custom Elements allow you to define new HTML elements with their own behavior:
class MyButton extends HTMLElement {
constructor() {
super();
// Attach Shadow DOM
this.attachShadow({ mode: 'open' });
// Create template
this.shadowRoot.innerHTML = `
<style>
button {
background: #007acc;
color: white;
border: none;
padding: 10px 20px;
cursor: pointer;
}
</style>
<button>
<slot></slot>
</button>
`;
}
connectedCallback() {
this.shadowRoot.querySelector('button')
.addEventListener('click', this.handleClick.bind(this));
}
handleClick() {
this.dispatchEvent(new CustomEvent('my-click', {
detail: { timestamp: Date.now() }
}));
}
}
customElements.define('my-button', MyButton);
Shadow DOM¶
Shadow DOM provides encapsulation for DOM structure and styling:
class IsolatedComponent extends HTMLElement {
constructor() {
super();
// Create Shadow DOM
const shadow = this.attachShadow({ mode: 'open' });
// Styles are scoped to this component
shadow.innerHTML = `
<style>
:host {
display: block;
padding: 20px;
border: 1px solid #ccc;
}
.title {
color: blue;
font-size: 18px;
}
</style>
<div class="title">
<slot name="title">Default Title</slot>
</div>
<div class="content">
<slot>Default content</slot>
</div>
`;
}
}
customElements.define('isolated-component', IsolatedComponent);
Lit Framework¶
Lit is a simple library for building fast, lightweight web components:
import { LitElement, html, css } from 'lit';
import { customElement, property } from 'lit/decorators.js';
@customElement('user-card')
export class UserCard extends LitElement {
static styles = css`
:host {
display: block;
padding: 16px;
border: 1px solid #ddd;
border-radius: 8px;
}
.avatar {
width: 50px;
height: 50px;
border-radius: 50%;
}
`;
@property() name = '';
@property() avatar = '';
@property({ type: Boolean }) online = false;
render() {
return html`
<div class="user">
<img class="avatar" src="${this.avatar}" alt="${this.name}">
<h3>${this.name}</h3>
<span class="status">${this.online ? 'Online' : 'Offline'}</span>
</div>
`;
}
}
Framework Integration¶
Web Components work with any framework:
<!-- React -->
<my-button onClick={handleClick}>Click me</my-button>
<!-- Vue -->
<my-button @my-click="handleClick">Click me</my-button>
<!-- Svelte -->
<my-button on:my-click={handleClick}>Click me</my-button>
Best Practices¶
- Use Lit for complex components - Better DX than vanilla Web Components
- Design for reusability - Make components framework-agnostic
- Proper event handling - Use CustomEvents for component communication
- Style encapsulation - Leverage Shadow DOM for style isolation
- Accessibility - Follow ARIA patterns and semantic HTML
Web Components provide a standards-based approach to building reusable UI components that work across frameworks and will continue to work as the web platform evolves.