Web Components
Also Known As
custom elements
shadow DOM
HTML templates
autonomous custom elements
TL;DR
Browser-native custom elements, shadow DOM, and HTML templates — framework-agnostic reusable components that work in React, Vue, plain HTML, and anywhere.
Explanation
Web Components three specs: Custom Elements (define <my-button> as a class extending HTMLElement), Shadow DOM (encapsulated DOM — styles and selectors don't leak in or out), HTML Templates (<template> not rendered until cloned). Custom element lifecycle: connectedCallback (added to DOM), disconnectedCallback (removed), attributeChangedCallback (observed attribute changed). Slots for content projection. Use cases: design systems that work in any framework, micro-frontend boundaries, widgets embedded in third-party pages.
Common Misconception
✗ Web Components require no JavaScript — Custom Elements require a JavaScript class definition; only HTML Templates can be declared without JS, but still need JS to instantiate and use.
Why It Matters
A design system built with Web Components works in React, Vue, Angular, and plain HTML — truly framework-agnostic components that survive technology changes.
Common Mistakes
- Shadow DOM when CSS customisation is needed — use CSS custom properties for theming instead
- Not calling super() first in the constructor — required for custom elements
- DOM manipulation in the constructor — use connectedCallback instead
- Not declaring static observedAttributes — attributeChangedCallback never fires without it
Code Examples
✗ Vulnerable
// React-only component — unusable outside React ecosystem:
const Button = ({ label, onClick }) => (
<button className="btn-primary" onClick={onClick}>{label}</button>
);
// Cannot use in Vue, Angular, plain HTML, or future frameworks
✓ Fixed
// Web Component — works everywhere:
class PrimaryButton extends HTMLElement {
static observedAttributes = ['disabled'];
connectedCallback() {
this.attachShadow({ mode: 'open' });
this.shadowRoot.innerHTML = `
<style>button { background: var(--btn-bg, blue); }</style>
<button part="button"><slot></slot></button>
`;
}
attributeChangedCallback(name, _, value) {
if (name === 'disabled')
this.shadowRoot.querySelector('button').disabled = !!value;
}
}
customElements.define('primary-button', PrimaryButton);
// <primary-button>Click me</primary-button> — works everywhere
Tags
🤝 Adopt this term
£79/year · your link shown here
Added
16 Mar 2026
Edited
22 Mar 2026
Views
24
🤖 AI Guestbook educational data only
|
|
Last 30 days
Agents 0
No pings yet today
Amazonbot 7
Google 5
Perplexity 2
Ahrefs 2
Majestic 1
ChatGPT 1
SEMrush 1
Also referenced
How they use it
crawler 18
crawler_json 1
Related categories
⚡
DEV INTEL
Tools & Severity
🔵 Info
⚙ Fix effort: High
⚡ Quick Fix
Define your custom element in a JS file, register with customElements.define(), and PHP renders <my-card> as plain HTML — the browser upgrades it when JS loads, giving progressive enhancement for free
📦 Applies To
javascript ES2018
web
🔗 Prerequisites
🔍 Detection Hints
Framework-specific components tied to React/Vue when vanilla custom elements would work across frameworks; no shadow DOM for style encapsulation
Auto-detectable:
✗ No
chrome-devtools
lighthouse
⚠ Related Problems
🤖 AI Agent
Confidence: Low
False Positives: High
✗ Manual fix
Fix: High
Context: File
Tests: Update