Signatur
Beschreibung
composedPath() liefert den Ereignispfad: ein Array aller EventTarget-Objekte, an denen der Listener aufgerufen wird. Das erste Element ist das innerste Ziel (z. B. ein <span> in einem Button), danach folgen die Vorfahren über document bis zu window.
Richtig nützlich wird die Methode beim Shadow DOM. Sobald ein Ereignis eine Shadow-Grenze verlässt, wird event.target auf den Host umgebogen (Retargeting). Außerhalb der Komponente sieht man also nur das Custom Element, nicht das Element im Inneren, das angeklickt wurde. Bei offenen Shadow Roots (mode: "open") enthält composedPath() trotzdem die inneren Knoten. Bei geschlossenen Shadow Roots (mode: "closed") tauchen sie nur auf, wenn der Listener selbst innerhalb dieses Shadow-Baums sitzt.
Typische Einsätze sind Klick-außerhalb-Erkennung bei Dropdowns und Modals, Event-Delegation über Komponentengrenzen hinweg und die Fehlersuche bei Bubbling-Problemen. Ob ein Ereignis die Shadow-Grenze überhaupt verlässt, hängt von der Eigenschaft composed ab. Native UI-Ereignisse wie click haben sie auf true, bei eigenen CustomEvents muss man composed: true selbst setzen.
Rückgabewert
EventTarget-Objekten, vom innersten Ziel bis zum äußersten (meist Window). Wird die Methode nicht während der Auslieferung aufgerufen (also nach Ende des Dispatch), ist das Array leer.Beispiele
Ereignispfad eines Klicks ausgeben
// HTML: <main><button id="save"><span>Speichern</span></button></main>
document.addEventListener('click', (event) => {
const path = event.composedPath().map((node) =>
node === window ? 'window'
: node === document ? 'document'
: node.nodeName.toLowerCase()
);
console.log(path.join(' → '));
});
Klick außerhalb erkennen – funktioniert auch mit Web Components
const dropdown = document.querySelector('my-dropdown');
const onOutsideClick = (event) => {
// contains() versagt bei Shadow DOM, composedPath() nicht
if (!event.composedPath().includes(dropdown)) {
dropdown.removeAttribute('open');
console.log('Dropdown geschlossen');
}
};
document.addEventListener('pointerdown', onOutsideClick);
Retargeting im offenen Shadow DOM umgehen
class FancyCard extends HTMLElement {
constructor() {
super();
const root = this.attachShadow({ mode: 'open' });
root.innerHTML = '<button class="like">Gefällt mir</button>';
}
}
customElements.define('fancy-card', FancyCard);
const card = document.createElement('fancy-card');
document.body.append(card);
document.addEventListener('click', (event) => {
console.log('target:', event.target.localName);
const inner = event.composedPath()[0];
console.log('wirklich geklickt:', inner.className);
});
card.shadowRoot.querySelector('.like').click();
CustomEvent mit composed über die Shadow-Grenze schicken
const host = document.createElement('div');
document.body.append(host);
const root = host.attachShadow({ mode: 'open' });
root.innerHTML = '<input id="q">';
document.addEventListener('search', (event) => {
console.log(event.composedPath().length > 0, event.detail);
});
// Ohne composed: true käme das Event nie bei document an
root.getElementById('q').dispatchEvent(
new CustomEvent('search', { detail: 'js', bubbles: true, composed: true })
);
// Wichtig · Fallstricke
- Nur während des Dispatch gültig: Wird
composedPath()später aufgerufen, etwa in einemsetTimeout, nach einemawaitoder für ein gespeichertes Event-Objekt, kommt ein leeres Array zurück. Wenn man den Pfad später braucht, sollte man ihn direkt im Listener in eine Variable kopieren. - Geschlossene Shadow Roots (
mode: "closed") werden außerhalb nicht offengelegt. Der Pfad endet für äußere Listener dann beim Host. - Ohne
composed: truebleibt ein Ereignis im eigenen Shadow-Baum. Außen kommt es gar nicht an, dort gibt es also auch keinen Pfad. - Bei Knoten, die nicht im Dokument hängen, endet der Pfad bei der Wurzel des losgelösten Teilbaums,
documentundwindowfehlen dann. Node.contains()ist für Klick-außerhalb-Prüfungen mit Web Components unzuverlässig, weil es keine Shadow-Grenzen überschreitet. Dafür istcomposedPath().includes()die robustere Lösung.- Kompatibilität: Chrome 53+, Firefox 52+, Safari 10+, Edge 79+. Die veraltete, nicht standardisierte Eigenschaft
event.path(nur Chrome) wurde entfernt, stattdessencomposedPath()verwenden.