v146 · Web Components · Registry Isolation

Registry Isolation

Three shadows each define <x-widget> differently using their own scoped CustomElementRegistry. Click the buttons to instantiate and inspect — each shadow resolves the tag to its own class, while the global registry has no <x-widget> registered at all.

Chrome 146 required for new CustomElementRegistry() and attachShadow({ registry }). Older browsers only have the global window.customElements registry — this demo will show an error and explain the fallback.

live demo

Registry A — <host-a>

#shadow-root (registry A) click "Create" above

Registry B — <host-b>

#shadow-root (registry B) click "Create" above

Global — window.customElements

window (no shadow) click "Check global registry"
Waiting for actions…

code

// --- Library A ---
const registryA = new CustomElementRegistry();

class WidgetA extends HTMLElement {
  connectedCallback() {
    this.style.cssText = 'display:block;padding:0.5rem;background:#e8f4f8;border:2px solid #4a90d9;';
    this.textContent = 'Widget from Library A';
  }
}
registryA.define('x-widget', WidgetA);

// --- Library B ---
const registryB = new CustomElementRegistry();

class WidgetB extends HTMLElement {
  connectedCallback() {
    this.style.cssText = 'display:block;padding:0.5rem;background:#f8e8e8;border:2px solid #d94a4a;';
    this.textContent = 'Widget from Library B';
  }
}
registryB.define('x-widget', WidgetB);

// --- Attach each to a shadow root ---
const hostA = document.createElement('div');
const shadowA = hostA.attachShadow({ mode: 'open', registry: registryA });
shadowA.innerHTML = '<x-widget></x-widget>';
document.body.appendChild(hostA);

const hostB = document.createElement('div');
const shadowB = hostB.attachShadow({ mode: 'open', registry: registryB });
shadowB.innerHTML = '<x-widget></x-widget>';
document.body.appendChild(hostB);

// Global registry: x-widget is NOT defined
console.log(customElements.get('x-widget')); // → undefined

see also