Start · Sprachen · JavaScript · Referenz · new CustomElementRegistry()

new CustomElementRegistry()

Methode

Erzeugt eine neue, eigenständige <code>CustomElementRegistry</code>, in der sich Custom Elements unabhängig von der globalen <code>window.customElements</code> für einzelne Shadow Roots registrieren lassen.

seit JavaScript Scoped Custom Element Registries: Safari 26+, Chro Kategorie: webapi

Signatur

new CustomElementRegistry()

Beschreibung

Bisher gab es pro Dokument genau eine Registry: window.customElements. Jeder Tag-Name wie <my-button> durfte nur einmal global registriert werden. Binden zwei Bibliotheken oder Micro-Frontends unterschiedliche Versionen derselben Komponente ein, kommt es zu Namenskonflikten und einem NotSupportedError beim zweiten define().

Mit dem Konstruktor new CustomElementRegistry() (Teil der Spezifikation Scoped Custom Element Registries) legst du eine bereichsbezogene Registry an. Du registrierst darin mit define() deine Elemente und hängst die Registry beim Erstellen eines Shadow Roots über die Option customElementRegistry von attachShadow() an. Alle Elemente, die innerhalb dieses Shadow Roots geparst oder erzeugt werden (z. B. über innerHTML), werden dann anhand dieser Registry aufgewertet – nicht anhand der globalen.

Typische Einsatzfälle sind Design-Systeme, die ihre internen Unterkomponenten kapseln wollen, Micro-Frontends mit unterschiedlichen Komponentenversionen und Widgets, die in fremde Seiten eingebettet werden. Die Registry bietet dieselben Methoden wie die globale (define(), get(), getName(), whenDefined(), upgrade()) sowie zusätzlich initialize(), um einen noch registrylosen Teilbaum an die Registry zu binden.

Rückgabewert

Typ
CustomElementRegistry
Beschreibung
Eine neue, leere CustomElementRegistry, die unabhängig von window.customElements ist und keine vordefinierten Elemente enthält.

Beispiele

Eigene Registry anlegen und einem Shadow Root zuweisen

class InnerButton extends HTMLElement {
  connectedCallback() {
    this.textContent = 'Scoped Button';
  }
}

// Neue, isolierte Registry erzeugen
const registry = new CustomElementRegistry();
registry.define('inner-button', InnerButton);

class AppCard extends HTMLElement {
  constructor() {
    super();
    const root = this.attachShadow({
      mode: 'open',
      customElementRegistry: registry
    });
    // Wird mit der Scoped Registry aufgewertet
    root.innerHTML = '<inner-button></inner-button>';
  }
}

customElements.define('app-card', AppCard);
document.body.append(document.createElement('app-card'));

console.log(customElements.get('inner-button'));
console.log(registry.get('inner-button') === InnerButton);
undefined true

Gleicher Tag-Name in zwei Versionen ohne Konflikt

class DatePickerV1 extends HTMLElement {
  connectedCallback() { this.textContent = 'Datepicker v1'; }
}
class DatePickerV2 extends HTMLElement {
  connectedCallback() { this.textContent = 'Datepicker v2'; }
}

const regA = new CustomElementRegistry();
const regB = new CustomElementRegistry();
regA.define('date-picker', DatePickerV1);
regB.define('date-picker', DatePickerV2);

const mount = (registry) => {
  const host = document.createElement('div');
  const root = host.attachShadow({ mode: 'open', customElementRegistry: registry });
  root.innerHTML = '<date-picker></date-picker>';
  document.body.append(host);
  return root.querySelector('date-picker').textContent;
};

console.log(mount(regA));
console.log(mount(regB));
Datepicker v1 Datepicker v2

Feature-Erkennung mit Fallback auf globale Registry

const supportsScopedRegistry = (() => {
  try {
    new CustomElementRegistry();
    return true;
  } catch {
    return false; // TypeError: Illegal constructor
  }
})();

const getRegistry = () =>
  supportsScopedRegistry ? new CustomElementRegistry() : window.customElements;

const registry = getRegistry();
console.log(supportsScopedRegistry ? 'Scoped Registry aktiv' : 'Fallback: global');
Scoped Registry aktiv (bzw. "Fallback: global" in älteren Browsern)

// Wichtig · Fallstricke

  • Browser-Kompatibilität: Neues Feature (Safari 26+, Chromium schrittweise). In älteren Browsern wirft new CustomElementRegistry() einen TypeError: Illegal constructor. Deshalb immer per try/catch prüfen oder ein Polyfill wie @webcomponents/scoped-custom-element-registry nutzen.
  • Frühe Entwürfe und Polyfills verwendeten die Option registry statt customElementRegistry in attachShadow(). Wenn du einen älteren Polyfill verwendest, prüfe, welchen Namen er erwartet.
  • Eine Scoped Registry erbt nichts von window.customElements. Global definierte Elemente werden im Shadow Root nicht automatisch aufgewertet, du musst sie dort erneut definieren.
  • Elemente, die außerhalb des Shadow Roots mit document.createElement() erzeugt werden, verwenden standardmäßig die globale Registry. Um das zu steuern, gib die Option customElementRegistry an oder füge den Inhalt über innerHTML im Shadow Root ein.
  • Auch in einer Scoped Registry darf eine Konstruktorklasse nur einmal pro Registry definiert werden. Ein doppeltes define() wirft einen NotSupportedError.