Event propagation
Wenn ein Event abgefeuert wird, durchläuft er verschiedene Phasen:
- die capturing phase
- die target phase
- die bubbling phase
Diese drei Ereignisse zusammen nennen wir event propagation.
The capturing phase
Section titled “The capturing phase”Der Weg der capturing phase geht von oben nach unten: window, document, dann folgt jedes Element bis das event target erreicht wird.
Wir müssen einem Event Listener explizit sagen, wenn er auf die capturing phase lauschen soll. Wir geben dem Event Listener ein drittes Argument, useCapture mit. useCapture ist ein Boolscher Wert, der Event Listener sieht dann also so aus:
document.addEventListener('event-name', callback, useCapture)Zur Veranschaulichung machen wir eine kleine Demo mit drei Boxen:
<div class="box box1"> <span>Box 1</span> <div class="box box2"> <span>Box 2</span> <div class="box box3"> <span>Box 3</span> </div> </div></div>Jede Box bekommt einen Event Listener, mit dem wir die eventPhase und das currentTarget abfragen.
const boxes = document.querySelectorAll('.box');
boxes.forEach(box => { box.addEventListener( 'click', e => { console.log(e.eventPhase, e.currentTarget); }, true, );});- wenn
eventPhase1 zurückgibt, sind wir in der capturing phase - wenn
eventPhase2 zurückgibt, sind wir in der target phase - wenn
eventPhase3 zurückgibt, sind wir in der bubbling phase

Ein Klick auf Box 1 ergibt
2 <div class="box box1>Ein Klick auf Box 2 ergibt
1 <div class="box box1">2 <div class="box box2">Ein Klick auf Box 3 ergibt
1 <div class="box box1">1 <div class="box box2">2 <div class="box box3">Zuerst feuern alle Elemente mit dem entsprechenden EventListener im DOM oberhalb des geklickten Elements (capturing phase), dann feuert das geklickte Element selbst (target phase).
The target phase
Section titled “The target phase”Die target phase sagt uns, dass JavaScript das Element, das den Event gefeuert hat, erreicht hat, und triggert alle Event Listener, die daran gebunden sind. Die target phase ignoriert die useCapture flag. Ob also true dabei steht oder nicht, ist egal.
const box3 = document.querySelector('.box3');
box3.addEventListener('click', e => {console.log(e.eventPhase, e.currentTarget)}, true);box3.addEventListener('click', e => {console.log(e.eventPhase, e.currentTarget)});
Ein Klick auf Box 3 ergibt
2 <div class="box box3">2 <div class="box box3">The bubbling phase
Section titled “The bubbling phase”Die bubbling phase geht den umgekehrten Weg: vom geklickten Element weg durch jedes Element durch bis zu document und window. Event Listener ohne useCapture flag werden in dieser Phase getriggert.
const boxes = document.querySelectorAll('.box');
boxes.forEach(box => { box.addEventListener('click', e => { console.log(e.eventPhase, e.currentTarget); } );});
Ein Klick auf Box 1 ergibt
2 <div class="box box1>Ein Klick auf Box 2 ergibt
2 <div class="box box2">3 <div class="box box1">Ein Klick auf Box 3 ergibt
2 <div class="box box3">3 <div class="box box2">3 <div class="box box1">Zuerst feuert also das geklickte Element (target phase), dann DOM-aufwärts alle weiteren Elemente, die diesen EventListener zugewiesen haben (bubbling phase).
Events that bubble
Section titled “Events that bubble”Bei Events, die bubbeln, ist die bubbles Eigenschaft true. Ein click Event bubbelt. blur und focus sind Events, die nicht bubbeln.
Event firing sequence
Section titled “Event firing sequence”Wenn zwei EventListener dem gleichen Element zugewiesen sind, feuert der EventListener, der zuerst zugewiesen wurde, auch als erstes.
const button = document.querySelector('button');button.addEventListener('click', e => console.log('First Event'));button.addEventListener('click', e => console.log('Second Event'));Prevent bubbling
Section titled “Prevent bubbling”Falls ein Event nicht bubbeln soll, kann man das mit stopPropagation oder stopImmediatePropagation verhindern.
stopPropagation()verhindert, dass Events nach oben bubbelnstopImmediatePropagation()verhindert, dass Events nach oben bubbeln und verhindert auch, dass weitere Events, die dem Element zugewiesen wurden, feuern.
const box2 = document.querySelector('.box2');const box3 = document.querySelector('.box3');
box2.addEventListener('click', e => console.log('Box 2 was clicked!'));box3.addEventListener('click', e => console.log('Box 3 was clicked!'));box3.addEventListener('click', e => e.stopPropagation());Ein Klick auf Box 2 ergibt
'Box 2 was clicked!'Ein Klick auf Box 3 ergibt
'Box 3 was clicked!'Events von Box 3 bubblen nicht mehr zu Box 2, weil wir stopPropagation() bei Box 3 aufgerufen haben.