Signatur
Beschreibung
Die schreibgeschützte Eigenschaft bubbles der Event-Schnittstelle gibt an, ob ein Ereignis die Bubbling-Phase durchläuft. Ist der Wert true, wird das Ereignis nach dem Auslösen am Zielelement nacheinander an alle Vorfahren bis zu document und window weitergereicht. Ist er false, endet die Weiterleitung nach der Zielphase. Die Capturing-Phase (von oben nach unten) findet jedoch in beiden Fällen statt.
Die meisten Benutzerereignisse wie click, input, keydown oder submit steigen im Baum auf. Einige wichtige Ereignisse tun das nicht, zum Beispiel focus, blur, mouseenter, mouseleave, load (auf Elementen) und scroll (auf Elementen). Dafür gibt es oft aufsteigende Gegenstücke wie focusin/focusout oder mouseover/mouseout.
Die Eigenschaft ist vor allem dann wichtig, wenn man Event-Delegation verwendet, also einen einzigen Listener auf ein Elternelement setzt, statt viele Listener auf einzelne Kindelemente. Das funktioniert nur mit Ereignissen, die aufsteigen. Bei eigenen Ereignissen, die mit new Event() oder new CustomEvent() erzeugt werden, ist bubbles standardmäßig false und muss über das Options-Objekt { bubbles: true } ausdrücklich eingeschaltet werden.
Rückgabewert
true, wenn das Ereignis im DOM-Baum aufsteigt, sonst false.Beispiele
Prüfen, ob ein Klick-Ereignis aufsteigt
document.addEventListener('click', (event) => {
console.log(`${event.type} bubbles:`, event.bubbles);
});
document.body.click();
Unterschied zwischen focus und focusin
const input = document.createElement('input');
document.body.append(input);
const log = (event) => console.log(event.type, event.bubbles);
input.addEventListener('focus', log);
input.addEventListener('focusin', log);
input.focus();
Eigenes Ereignis mit Bubbling für Event-Delegation
const list = document.createElement('ul');
const item = document.createElement('li');
item.textContent = 'Eintrag 1';
list.append(item);
document.body.append(list);
// Ein Listener am Elternelement fängt Ereignisse aller Kinder ab
list.addEventListener('item-selected', (event) => {
console.log('Ausgewählt:', event.target.textContent, '| bubbles:', event.bubbles);
});
// Ohne bubbles: true würde der Listener an <ul> nie ausgelöst
const noBubble = new CustomEvent('item-selected');
item.dispatchEvent(noBubble);
console.log('Ohne Bubbling:', noBubble.bubbles);
item.dispatchEvent(new CustomEvent('item-selected', { bubbles: true }));
Generischer Handler, der nicht aufsteigende Ereignisse per Capturing abfängt
const form = document.querySelector('form') ?? document.body;
const handler = (event) => {
// Nicht aufsteigende Ereignisse erreichen das Formular nur in der Capturing-Phase
const phase = event.bubbles ? 'Bubbling/Capturing' : 'nur Capturing';
console.log(`${event.type} an <${event.target.tagName.toLowerCase()}> (${phase})`);
};
// capture: true sorgt dafür, dass auch 'blur' ankommt
form.addEventListener('blur', handler, { capture: true });
// Wichtig · Fallstricke
- Schreibgeschützt: Eine Zuweisung wie
event.bubbles = truewird still ignoriert (im Strict Mode gibt es einenTypeError). Der Wert lässt sich nur beim Erzeugen übernew Event(type, { bubbles: true })festlegen. - Standardwert bei eigenen Ereignissen:
new Event()undnew CustomEvent()steigen standardmäßig nicht auf. Das ist ein häufiger Grund, warum delegierte Listener nicht ausgelöst werden. - Nicht mit
stopPropagation()verwechseln:bubblesbleibt auch nachevent.stopPropagation()auftrue. Ob die Weiterleitung tatsächlich abgebrochen wurde, verrät die Eigenschaft nicht. - Shadow DOM: Damit ein aufsteigendes Ereignis die Grenze eines Shadow Root überschreitet, ist zusätzlich
composed: truenötig. - Nicht aufsteigende Ereignisse lassen sich trotzdem an einem Vorfahren abfangen, wenn man den Listener mit
{ capture: true }registriert. - Die Eigenschaft wird von allen Browsern unterstützt. Das veraltete
event.initEvent(type, bubbles, cancelable)sollte man nicht mehr verwenden, sondern den Konstruktor nutzen.