Signatur
Beschreibung
Die Eigenschaft composed zeigt an, ob ein Ereignis beim Propagieren die Grenze eines Shadow-DOM überschreiten darf. Ist der Wert true, läuft das Ereignis aus der Shadow-Root heraus weiter zum Host-Element und durch das umgebende Dokument. Ist er false, endet die Propagation an der Shadow-Root.
Die meisten vom Browser ausgelösten UI-Ereignisse wie click, input, keydown, focus oder pointerdown haben composed: true. Andere Ereignisse, etwa load, change, scroll, slotchange oder toggle, sind composed: false. Selbst erzeugte Ereignisse (new Event(), new CustomEvent()) sind standardmäßig nicht composed. Bei ihnen muss man die Option composed: true im Konstruktor ausdrücklich setzen.
Wenn ein composed-Ereignis die Shadow-Grenze überschreitet, wird es retargetiert: Für Listener außerhalb der Komponente zeigt event.target auf das Host-Element und nicht auf das innere Element. Den vollständigen Pfad samt innerer Knoten liefert event.composedPath(), allerdings nur bei offenen Shadow-Roots (mode: "open").
Man braucht die Eigenschaft vor allem bei der Entwicklung von Web Components. Damit legt man fest, ob eigene Ereignisse zur öffentlichen Schnittstelle der Komponente gehören (composed: true) oder nur intern gelten.
Rückgabewert
true, wenn das Ereignis die Shadow-DOM-Grenze überschreitet, sonst false. Der Wert wird bei der Erzeugung festgelegt und ist schreibgeschützt.Beispiele
composed bei nativen Ereignissen prüfen
document.addEventListener('click', (e) => {
console.log('click composed:', e.composed);
});
window.addEventListener('load', (e) => {
console.log('load composed:', e.composed);
});
Eigenes Ereignis aus einer Web Component nach außen senden
class LikeButton extends HTMLElement {
constructor() {
super();
const root = this.attachShadow({ mode: 'open' });
root.innerHTML = '<button>Gefällt mir</button>';
root.querySelector('button').addEventListener('click', () => {
// bubbles + composed: Ereignis verlässt die Shadow-Root
this.shadowRoot.querySelector('button').dispatchEvent(
new CustomEvent('like', { bubbles: true, composed: true, detail: { id: 42 } })
);
});
}
}
customElements.define('like-button', LikeButton);
document.body.append(document.createElement('like-button'));
document.addEventListener('like', (e) => {
console.log(e.composed, e.target.tagName, e.detail.id);
});
Unterschied composed: true vs. false
const host = document.createElement('div');
document.body.append(host);
const root = host.attachShadow({ mode: 'open' });
const inner = document.createElement('span');
root.append(inner);
document.body.addEventListener('ping', (e) => {
console.log('Body empfängt ping, composed =', e.composed);
});
inner.dispatchEvent(new Event('ping', { bubbles: true })); // bleibt in der Shadow-Root
inner.dispatchEvent(new Event('ping', { bubbles: true, composed: true })); // erreicht body
// Wichtig · Fallstricke
- Standardwert
false: Selbst erzeugte Ereignisse verlassen eine Shadow-Root nur mitcomposed: true. Das wird häufig vergessen, und dann erreicht das Ereignis Listener außerhalb der Komponente nicht. composedersetzt nichtbubbles: Ohnebubbles: trueerreicht ein composed-Ereignis nur den Host selbst, aber nicht dessen Vorfahren.- Retargeting: Außerhalb der Komponente zeigt
event.targetauf das Host-Element. Das innere Ziel findet man überevent.composedPath(). Bei geschlossenen Shadow-Roots (mode: "closed") fehlen die inneren Knoten im Pfad. - Schreibgeschützt: Eine Zuweisung wie
e.composed = truewird stillschweigend ignoriert und löst im strikten Modus einenTypeErroraus. - Kapselung: Setze
composed: truenur bei Ereignissen, die zur öffentlichen Schnittstelle der Komponente gehören. Sonst gelangen interne Implementierungsdetails nach außen. - Kompatibilität: Unterstützt in allen modernen Browsern (Chrome 53+, Firefox 52+, Safari 10+, Edge 79+). Nicht verfügbar im Internet Explorer.