Start · Sprachen · JavaScript · Referenz · Element.attachShadow()

Element.attachShadow()

Methode

Hängt einen Shadow-DOM-Baum an ein Element an und gibt dessen <code>ShadowRoot</code> zurück – Grundlage für gekapselte Web Components.

seit JavaScript Baseline: alle modernen Browser (seit 2020) Kategorie: webapi

Signatur

Element.prototype.attachShadow(options)

Beschreibung

attachShadow() erzeugt für ein Element (den Shadow Host) einen eigenen, vom übrigen Dokument abgekapselten DOM-Teilbaum. Markup und Styles in diesem Shadow DOM werden nicht von den Selektoren und CSS-Regeln der umgebenden Seite erfasst, und umgekehrt gelangen Styles aus dem Shadow DOM nicht nach außen. Das ist die Grundlage für wiederverwendbare Web Components, deren Aussehen und Verhalten nicht durch fremden Code zerstört werden kann.

Üblicherweise wird die Methode im Konstruktor eines Custom Elements aufgerufen (this.attachShadow({ mode: 'open' })). Der Inhalt der Light-DOM-Kinder des Hosts lässt sich über <slot>-Elemente in den Shadow-Baum projizieren.

Über die Option mode legt man fest, ob der Shadow Root von außen über element.shadowRoot erreichbar ist ('open') oder nicht ('closed'). Weitere Optionen steuern Fokus-Delegation, Slot-Zuweisung, Klonbarkeit und Serialisierbarkeit.

Nicht jedes Element kann einen Shadow Root erhalten: erlaubt sind autonome Custom Elements (mit gültigem Namen) sowie article, aside, blockquote, body, div, footer, h1–h6, header, main, nav, p, section und span.

Parameter

Name Typ Default Beschreibung
$options Pflicht Object Konfigurationsobjekt für den Shadow Root.
$options.mode Pflicht 'open' | 'closed' 'open': Shadow Root über element.shadowRoot erreichbar. 'closed': element.shadowRoot liefert null; nur die zurückgegebene Referenz erlaubt Zugriff.
$options.delegatesFocus boolean false Bei true wird ein Klick auf nicht fokussierbare Teile des Hosts an das erste fokussierbare Element im Shadow DOM weitergeleitet; der Host erhält :focus-Styling.
$options.slotAssignment 'named' | 'manual' 'named' 'named': automatische Zuweisung über das slot-Attribut. 'manual': Zuweisung per HTMLSlotElement.assign().
$options.clonable boolean false Bei true wird der Shadow Root beim cloneNode() bzw. importNode() des Hosts mitkopiert.
$options.serializable boolean false Bei true kann der Shadow Root mit getHTML({ serializableShadowRoots: true }) serialisiert werden.

Rückgabewert

Typ
ShadowRoot
Beschreibung
Der neu erzeugte ShadowRoot, in den Inhalte (z. B. per innerHTML, append()) eingefügt werden können.

Beispiele

Shadow DOM an ein div anhängen

const host = document.createElement('div');
document.body.append(host);

const shadow = host.attachShadow({ mode: 'open' });
shadow.innerHTML = `
  <style>p { color: crimson; }</style>
  <p>Ich bin gekapselt.</p>
`;

// Globale <p>-Styles wirken hier nicht – und crimson wirkt nicht außerhalb
console.log(host.shadowRoot === shadow);
console.log(document.querySelector('p')); // Shadow-Inhalt ist nicht sichtbar
true null

Web Component mit Slot

class InfoBox extends HTMLElement {
  constructor() {
    super();
    const shadow = this.attachShadow({ mode: 'open' });
    shadow.innerHTML = `
      <style>
        :host { display: block; border: 1px solid #0a7; padding: .5rem; }
        h2 { margin: 0; font-size: 1rem; }
      </style>
      <h2><slot name="titel">Hinweis</slot></h2>
      <slot></slot>
    `;
  }
}
customElements.define('info-box', InfoBox);

document.body.insertAdjacentHTML('beforeend', `
  <info-box>
    <span slot="titel">Achtung</span>
    Die Wartung beginnt um 22 Uhr.
  </info-box>
`);

Geschlossener Shadow Root mit privater Referenz

class SecretCounter extends HTMLElement {
  #root;
  #count = 0;
  constructor() {
    super();
    this.#root = this.attachShadow({ mode: 'closed', delegatesFocus: true });
    this.#root.innerHTML = '<button>0</button>';
    this.#root.querySelector('button').addEventListener('click', (e) => {
      e.target.textContent = ++this.#count;
    });
  }
}
customElements.define('secret-counter', SecretCounter);

const el = document.createElement('secret-counter');
document.body.append(el);
console.log(el.shadowRoot);
null

Fehler bei nicht unterstützten Elementen abfangen

const tryAttach = (el) => {
  try {
    el.attachShadow({ mode: 'open' });
    return 'ok';
  } catch (err) {
    return err.name;
  }
};

console.log(tryAttach(document.createElement('section')));
console.log(tryAttach(document.createElement('img')));
const div = document.createElement('div');
tryAttach(div);
console.log(tryAttach(div)); // zweiter Aufruf
ok NotSupportedError NotSupportedError

// Wichtig · Fallstricke

  • Nur einmal pro Element: Ein zweiter Aufruf wirft einen NotSupportedError (Ausnahme: ein per deklarativem Shadow DOM erzeugter Root mit gleichem mode wird geleert und zurückgegeben).
  • Nicht unterstützte Elemente (z. B. img, input, a, button) sowie angepasste eingebaute Elemente mit ungültigem Namen werfen NotSupportedError.
  • 'closed' ist keine Sicherheitsgrenze: Fremde Skripte können z. B. Element.prototype.attachShadow überschreiben und die Referenz abgreifen. Für vertrauliche Daten nicht darauf verlassen.
  • XSS: Shadow DOM schützt nicht vor Skript-Injektion. Nutzerdaten nicht ungefiltert per shadow.innerHTML einfügen – lieber textContent oder DOM-Methoden verwenden.
  • Events aus dem Shadow DOM werden beim Verlassen retargetiert (event.target zeigt auf den Host); eigene Events brauchen composed: true, um die Grenze zu überschreiten.
  • Kompatibilität: mode und delegatesFocus werden in allen modernen Browsern unterstützt; slotAssignment, clonable und serializable sind neuer und sollten bei älteren Browsern geprüft werden. Der Internet Explorer unterstützt Shadow DOM nicht.