Signatur
Beschreibung
Jeder ShadowRoot gehört zu genau einem Element, dem Shadow Host. Die Eigenschaft host gibt eine Referenz auf dieses Element zurück. Das ist die Gegenrichtung zu Element.shadowRoot: Vom Host kommt man über element.shadowRoot in den Schatten-Baum, und von innen führt shadowRoot.host wieder heraus zum Host.
Gebraucht wird das vor allem in Web Components: Code, der im Schatten-Baum läuft, etwa ein Event-Handler auf einem inneren Button, kann über node.getRootNode().host die zugehörige Komponente finden. Dort liest er dann Attribute, setzt Zustände oder löst eigene Events am Host aus. Auch Bibliotheken nutzen host, um beim Durchlaufen des DOM über Shadow-Grenzen hinweg nach oben zu gehen.
Die Eigenschaft ist schreibgeschützt. Ein Shadow Root lässt sich nicht nachträglich an ein anderes Element hängen, und zu jedem Host gehört höchstens ein Shadow Root. Mit mode: "closed" gibt element.shadowRoot von außen null zurück. Wer eine Referenz auf den Root hat, erreicht über host aber trotzdem das Host-Element.
Rückgabewert
ShadowRoot angehängt ist. Es ist immer gesetzt und nie null.Beispiele
Host aus einem Shadow Root ermitteln
const div = document.createElement('div');
div.id = 'widget';
const root = div.attachShadow({ mode: 'open' });
console.log(root.host === div);
console.log(root.host.id);
console.log(div.shadowRoot === root);
Aus einem inneren Event-Handler die Komponente erreichen
class LikeButton extends HTMLElement {
constructor() {
super();
const root = this.attachShadow({ mode: 'open' });
root.innerHTML = '<button type="button">Gefällt mir</button>';
root.querySelector('button').addEventListener('click', (event) => {
// Vom inneren Button zum Host (der Komponente) gelangen
const host = event.currentTarget.getRootNode().host;
const count = Number(host.dataset.count ?? 0) + 1;
host.dataset.count = count;
host.dispatchEvent(new CustomEvent('like', { detail: { count }, bubbles: true, composed: true }));
});
}
}
customElements.define('like-button', LikeButton);
const btn = document.createElement('like-button');
document.body.append(btn);
btn.addEventListener('like', (e) => console.log('Likes:', e.detail.count));
btn.shadowRoot.querySelector('button').click();
DOM über Shadow-Grenzen hinweg nach oben durchlaufen
// Liefert den nächsten Vorfahren, der auf den Selektor passt, auch über Shadow Roots hinweg
const closestComposed = (node, selector) => {
let current = node;
while (current) {
if (current instanceof Element && current.matches(selector)) return current;
current = current.parentNode instanceof ShadowRoot
? current.parentNode.host
: current.parentNode;
}
return null;
};
const section = document.createElement('section');
section.className = 'card';
const host = document.createElement('div');
section.append(host);
const inner = document.createElement('span');
host.attachShadow({ mode: 'open' }).append(inner);
console.log(inner.closest('.card'));
console.log(closestComposed(inner, '.card') === section);
// Wichtig · Fallstricke
- Schreibgeschützt: Eine Zuweisung an
hostwird im nicht-strikten Modus stillschweigend ignoriert und löst im Strict Mode einenTypeErroraus. - Nur auf ShadowRoot:
getRootNode()gibt für normale Knoten dasDocumentzurück, und das hat keine Eigenschafthost(Ergebnis:undefined). Vor dem Zugriff mitroot instanceof ShadowRootprüfen. - Geschlossene Shadow Roots: Mit
mode: "closed"kann manhostnur lesen, wenn man eine Referenz auf den Root hat, etwa übergetRootNode()von innen. Die Kapselung ist damit kein Sicherheitsmechanismus. - Kein Umhängen: Der Host bleibt für die ganze Lebensdauer des Shadow Roots gleich. Ein Element kann nur einen Shadow Root haben, ein zweiter Aufruf von
attachShadow()löst eineNotSupportedError-DOMExceptionaus. - Kompatibilität: Wird in Chrome/Edge 53+, Firefox 63+ und Safari 10+ unterstützt. In sehr alten Browsern nur über Polyfills (Shadow DOM v0 ist veraltet).