Start · Sprachen · JavaScript · Referenz · ElementInternals.shadowRoot

ElementInternals.shadowRoot

Eigenschaft

Gibt den <code>ShadowRoot</code> des Custom-Element-Hosts zurück, auch wenn er geschlossen (<code>mode: "closed"</code>) ist. Ohne Shadow Root ist der Wert <code>null</code>.

seit JavaScript Baseline 2023 (Chrome/Edge 88+, Firefox 93+, Safar Kategorie: webapi

Signatur

ElementInternals.shadowRoot

Beschreibung

Die schreibgeschützte Eigenschaft shadowRoot des ElementInternals-Objekts liefert den ShadowRoot des zugehörigen Custom Elements. Das Objekt bekommen Sie über this.attachInternals(). Anders als Element.shadowRoot gibt die Eigenschaft auch geschlossene Shadow Roots (mode: "closed") zurück. Das ist sicher, weil nur die Komponente selbst eine Referenz auf ihr ElementInternals-Objekt hat.

Am häufigsten brauchen Sie die Eigenschaft bei Declarative Shadow DOM. Wenn der Server das Markup mit <template shadowrootmode="closed"> ausliefert, legt der Parser den Shadow Root schon an, bevor die Klasse des Custom Elements registriert ist. Einen Rückgabewert von attachShadow(), den Sie speichern könnten, gibt es dann nicht. Über internals.shadowRoot findet die Komponente den vorgerenderten Shadow Root trotzdem und kann ihn „hydratisieren“ (also mit Logik versehen), statt ihn neu aufzubauen.

Hat das Element noch keinen Shadow Root, ist der Wert null. Das gilt auch, wenn der Shadow Root für ElementInternals nicht freigegeben ist, etwa weil er vor dem Upgrade zum Custom Element per attachShadow() angelegt wurde. Typisch ist deshalb dieses Muster: erst internals.shadowRoot prüfen und nur bei null selbst attachShadow() aufrufen.

Rückgabewert

Typ
ShadowRoot | null
Beschreibung
Der ShadowRoot des Host-Elements, egal ob offen oder geschlossen. null, wenn kein Shadow Root existiert oder er für ElementInternals nicht verfügbar ist.

Beispiele

Zugriff auf einen geschlossenen Shadow Root

class SecretBox extends HTMLElement {
  #internals = this.attachInternals();

  constructor() {
    super();
    // Rückgabewert von attachShadow wird bewusst nicht gespeichert
    this.attachShadow({ mode: 'closed' });
    this.#internals.shadowRoot.innerHTML = '<p>Geheim!</p>';
  }

  connectedCallback() {
    console.log('Von außen:', this.shadowRoot);
    console.log('Intern:', this.#internals.shadowRoot.mode);
  }
}

customElements.define('secret-box', SecretBox);
document.body.append(document.createElement('secret-box'));
Von außen: null Intern: closed

Declarative Shadow DOM hydratisieren oder neu anlegen

// HTML vom Server:
// <my-counter>
//   <template shadowrootmode="closed">
//     <button>0</button>
//   </template>
// </my-counter>

class MyCounter extends HTMLElement {
  #internals = this.attachInternals();
  #count = 0;

  constructor() {
    super();
    let root = this.#internals.shadowRoot;

    if (!root) {
      // Kein vorgerendertes Markup: Shadow Root selbst erzeugen
      root = this.attachShadow({ mode: 'closed' });
      root.innerHTML = '<button>0</button>';
      console.log('Client-seitig erzeugt');
    } else {
      console.log('Vorhandenen Shadow Root übernommen');
    }

    const button = root.querySelector('button');
    button.addEventListener('click', () => {
      button.textContent = ++this.#count;
    });
  }
}

customElements.define('my-counter', MyCounter);
Vorhandenen Shadow Root übernommen

Wert vor und nach attachShadow()

class DemoEl extends HTMLElement {
  constructor() {
    super();
    const internals = this.attachInternals();
    console.log(internals.shadowRoot);        // noch kein Shadow Root
    const root = this.attachShadow({ mode: 'open' });
    console.log(internals.shadowRoot === root);
  }
}

customElements.define('demo-el', DemoEl);
new DemoEl();
null true

// Wichtig · Fallstricke

  • Nur für autonome Custom Elements: attachInternals() gibt es nur bei autonomen Custom Elements. Bei eingebauten Elementen mit is-Attribut oder bei normalen Elementen wirft der Aufruf einen NotSupportedError. Außerdem darf attachInternals() pro Element nur einmal aufgerufen werden.
  • Kapselung wahren: Speichern Sie das ElementInternals-Objekt in einem privaten Feld (#internals), nicht in einer öffentlichen Eigenschaft. Sonst kann fremder Code darüber auf einen geschlossenen Shadow Root zugreifen, und mode: "closed" bringt nichts mehr.
  • Schreibgeschützt: Die Eigenschaft hat keinen Setter. Eine Zuweisung wird ignoriert bzw. wirft im Strict Mode einen TypeError. Einen Shadow Root erzeugen Sie nur mit attachShadow() oder deklarativ per <template shadowrootmode>.
  • Kann null sein: Prüfen Sie den Wert vor der Verwendung. Nach dem Upgrade liefert die Eigenschaft auch dann null, wenn das Element vor dem Upgrade schon einen Shadow Root per attachShadow() bekommen hat.
  • Kompatibilität: Wird von allen aktuellen Browsern unterstützt (Chromium 88+, Firefox 93+, Safari 16.4+). Ältere Safari-Versionen haben kein ElementInternals. Dort helfen Feature-Erkennung ('attachInternals' in HTMLElement.prototype) oder ein Polyfill.