← CodeClarityLab Home
Browse by Category
+ added · updated 7d
← Back to glossary

Web Components

javascript ES2018 Advanced

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

Added 16 Mar 2026
Edited 22 Mar 2026
Views 24
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings W 0 pings T 0 pings F 0 pings S 1 ping S 0 pings M 0 pings T 1 ping W 0 pings T 0 pings F 0 pings S 1 ping S 0 pings M 0 pings T 1 ping W 0 pings T 0 pings F 3 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 1 ping F 1 ping S 0 pings S 0 pings M 0 pings T 1 ping W 0 pings T
No pings yet today
Amazonbot 7 Google 5 Perplexity 2 Ahrefs 2 Majestic 1 ChatGPT 1 SEMrush 1
crawler 18 crawler_json 1
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

✓ schema.org compliant