1237

What is the difference between event bubbling and capturing? When should one use bubbling vs capturing?

TylerH
  • 20,799
  • 66
  • 75
  • 101
Arun P Johny
  • 384,651
  • 66
  • 527
  • 531
  • 8
    I recommend this useful link: https://javascript.info/bubbling-and-capturing – MeirDayan Feb 20 '20 at 11:15
  • @CommunityAns: this site is excellent, but this topic, particularly, is depicted in a somewhat confusing way. – Veverke Jun 22 '20 at 08:38
  • 1
    Needing engineers to be aware of the difference of both, and have code that can be broken simply by choosing an "incorrect" propagation type, is in my opinion a code-smell (or anti-pattern). A better way to go about it is to just enforce a coding style where propagation type doesn't matter. – Chris Vilches Jan 06 '22 at 07:42

11 Answers11

1737

Event bubbling and capturing are two ways of event propagation in the HTML DOM API, when an event occurs in an element inside another element, and both elements have registered a handle for that event. The event propagation mode determines in which order the elements receive the event.

With bubbling, the event is first captured and handled by the innermost element and then propagated to outer elements.

With capturing, the event is first captured by the outermost element and propagated to the inner elements.

Capturing is also called "trickling", which helps remember the propagation order:

trickle down, bubble up

Back in the old days, Netscape advocated event capturing, while Microsoft promoted event bubbling. Both are part of the W3C Document Object Model Events standard (2000).

IE < 9 uses only event bubbling, whereas IE9+ and all major browsers support both. On the other hand, the performance of event bubbling may be slightly lower for complex DOMs.

We can use the addEventListener(type, listener, useCapture) to register event handlers for in either bubbling (default) or capturing mode. To use the capturing model pass the third argument as true.

Example

<div>
    <ul>
        <li></li>
    </ul>
</div>

In the structure above, assume that a click event occurred in the li element.

In capturing model, the event will be handled by the div first (click event handlers in the div will fire first), then in the ul, then at the last in the target element, li.

In the bubbling model, the opposite will happen: the event will be first handled by the li, then by the ul, and at last by the div element.

For more information, see

In the example below, if you click on any of the highlighted elements, you can see that the capturing phase of the event propagation flow occurs first, followed by the bubbling phase.

var logElement = document.getElementById('log');

function log(msg) {
    logElement.innerHTML += ('<p>' + msg + '</p>');
}

function capture() {
    log('capture: ' + this.firstChild.nodeValue.trim());
}

function bubble() {
    log('bubble: ' + this.firstChild.nodeValue.trim());
}

function clearOutput() {
    logElement.innerHTML = "";
}

var divs = document.getElementsByTagName('div');
for (var i = 0; i < divs.length; i++) {
    divs[i].addEventListener('click', capture, true);
    divs[i].addEventListener('click', bubble, false);
}
var clearButton = document.getElementById('clear');
clearButton.addEventListener('click', clearOutput);
p {
    line-height: 0;
}

div {
    display:inline-block;
    padding: 5px;

    background: #fff;
    border: 1px solid #aaa;
    cursor: pointer;
}

div:hover {
    border: 1px solid #faa;
    background: #fdd;
}
<div>1
    <div>2
        <div>3
            <div>4
                <div>5</div>
            </div>
        </div>
    </div>
</div>
<button id="clear">clear output</button>
<section id="log"></section>

Another example at JSFiddle.

subject-q
  • 91
  • 3
  • 19
Arun P Johny
  • 384,651
  • 66
  • 527
  • 531
  • 45
    `useCapture` now supported in IE >= 9. [source](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget.addEventListener#Browser_compatibility) – beatgammit Aug 20 '13 at 17:10
  • 8
    I know its too late to put comment but nice article i found here http://catcode.com/domcontent/events/capture.html – Just code Oct 18 '13 at 09:56
  • 4
    Is `triclkling` the same as `capturing`? Crockford talks about `Trickling v. Bubbling` in this video talk - https://www.youtube.com/watch?v=Fv9qT9joc0M&list=PL7664379246A246CB around `1 hr 5 minutes`. – Kevin Meredith Jan 02 '14 at 19:25
  • 1
    @KevinMeredith Same thing. "Trickling" just makes it easier to remember what the two models do (trickle *down*, bubble *up*). – a cat Mar 01 '14 at 15:25
  • @Arun P Johny, I was look ing for this diffination, Thank you very much, Can you please give an example or jsfiddle demo will be much helpful. – RONE Sep 17 '14 at 05:47
  • @ArunPJohny: Thanks for being open to improvements. I've edited the post. Only one problem - I couldn't understand the sentence marked with "(?)". – Dan Dascalescu Oct 22 '14 at 05:07
  • 1
    @DanDascalescu thanks.. what it means is... when an event for example click happens... the capture phase will happen, ie capture handlers from the document object down till the actual event target will executed first.. then the bubbling phase will get executed... ie bubble handlers attached to the target will execute first then it will propagate upwards till the document object... Does it make sense? If you try the examples it might get little more clear – Arun P Johny Oct 22 '14 at 05:14
  • 12
    The answer above correct in regards to the order in the detailed explanation, but leaves you thinking that trickle occurs second with "bubble up, trickle down". Events always go through the capture phase before the bubble phase. The correct order is `trickle down` => `onElement` => `bubble up` – runspired Dec 23 '15 at 14:59
  • All the events on ancestor elements, if in capturing mode will execute first irrespective of the element clicked has bubbling or capturing parameter set. Why do I feel this thing is not explained well in the answer. @ArunPJohny . Edit: I am considering the mix usage of bubbling and capturing. – Birju Shah Mar 16 '16 at 11:15
  • 1
    Does an event continue to bubble up/trickle down even if it has already been handled? In the
    • example above, in case all three elements have handlers for click event, and user clicks on
    • , will the click handlers for
        and
        also execute (assuming event bubbling)?
    – darKnight Jun 21 '16 at 17:06
  • 2
    "With bubbling, the event is first captured and handled by the innermost element and then propagated to outer elements." -- You should point out that not all events bubble (e.g., `focus`). – thdoan Jun 18 '18 at 10:41
  • 1
    @runspired I think this isn't completely true, or at least there is a special case to consider. I edited the code snippet and swapped the two lines of code such that the bubble event listeners were added before the capture event listeners. The result I got was: capture: 1 capture: 2 capture: 3 capture: 4 bubble: 5 capture: 5 bubble: 4 bubble: 3 bubble: 2 bubble: 1 It would seem that the outermost element is a special case. Bubble 5 happened before Capture 5. For the outermost element, it would seem that event handlers are executed in the order they were registered in. – Kevin Wheeler Jul 28 '20 at 04:37
  • ps: the last capturing and the first bubbling in the code snippet's output are in fact in the target phase (AT_TARGET). the capturing and bubbling phase does not include the event.target. i.e: the third argument of EventTarget.addEventListener() is import only when the EventTarget is an ancestor of the current event.target. modified example: https://jsfiddle.net/Archangelll/we76k0fb/ –  Jul 16 '21 at 19:18
  • is there any reason why capturing happens *before* bubbling? – Minh Nghĩa Apr 07 '22 at 05:56
572

Description:

quirksmode.org has a nice description of this. In a nutshell (copied from quirksmode):

Event capturing

When you use event capturing

               | |
---------------| |-----------------
| element1     | |                |
|   -----------| |-----------     |
|   |element2  \ /          |     |
|   -------------------------     |
|        Event CAPTURING          |
-----------------------------------

the event handler of element1 fires first, the event handler of element2 fires last.

Event bubbling

When you use event bubbling

               / \
---------------| |-----------------
| element1     | |                |
|   -----------| |-----------     |
|   |element2  | |          |     |
|   -------------------------     |
|        Event BUBBLING           |
-----------------------------------

the event handler of element2 fires first, the event handler of element1 fires last.


What to use?

It depends on what you want to do. There is no better. The difference is the order of the execution of the event handlers. Most of the time it will be fine to fire event handlers in the bubbling phase but it can also be necessary to fire them earlier.

Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • 1
    Does not both happens, first capturing and then bubbling, also what is dispatch event? – Suraj Jain Apr 06 '18 at 04:31
  • 1
    a graphical example is here: https://javascript.info/bubbling-and-capturing – MeirDayan Feb 20 '20 at 11:19
  • 1
    Capture phase handlers are particularly useful when some element's code (code you don't control, like a plugin) is stopping propagation, and you really want to know when that event occurs. You can pick it up on the way to them instead of on the way back. You might not get it in the bubbling phase if they stopped its propagation. – doug65536 Nov 20 '21 at 04:48
84

If there are two elements element 1 and element 2. Element 2 is inside element 1 and we attach an event handler with both the elements lets say onClick. Now when we click on element 2 then eventHandler for both the elements will be executed. Now here the question is in which order the event will execute. If the event attached with element 1 executes first it is called event capturing and if the event attached with element 2 executes first this is called event bubbling. As per W3C the event will start in the capturing phase until it reaches the target comes back to the element and then it starts bubbling

The capturing and bubbling states are known by the useCapture parameter of addEventListener method

eventTarget.addEventListener(type,listener,[,useCapture]);

By Default useCapture is false. It means it is in the bubbling phase.

var div1 = document.querySelector("#div1");
var div2 = document.querySelector("#div2");

div1.addEventListener("click", function (event) {
  alert("you clicked on div 1");
}, true);

div2.addEventListener("click", function (event) {
  alert("you clicked on div 2");
}, false);
#div1{
  background-color:red;
  padding: 24px;
}

#div2{
  background-color:green;
}
<div id="div1">
  div 1
  <div id="div2">
    div 2
  </div>
</div>

Please try with changing true and false.

dinesh_malhotra
  • 1,829
  • 17
  • 10
  • 3
    @masterxilo: no need for Fiddle, StackOverflow now supports [inline code (stack snippets)](http://blog.stackoverflow.com/2014/09/introducing-runnable-javascript-css-and-html-code-snippets/). – Dan Dascalescu Oct 22 '14 at 08:10
  • Regarding `the event will start in the capturing phase untill it reaches the target comes back to the element and then it starts bubbling`. I only found the [addEventListener](https://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-flow) has the parameter `useCapture` which can be set to true or false; and [in HTML 4.0, event listeners were specified as attributes of an element](https://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-EventListener) and `useCapture defaults to false`. Could you link to a spec that confirms what you wrote? – surfmuggle Nov 20 '16 at 22:18
38

I have found this tutorial at javascript.info to be very clear in explaining this topic. And its 3-points summary at the end is really talking to the crucial points. I quote it here:

  1. Events first are captured down to deepest target, then bubble up. In IE<9 they only bubble.
  2. All handlers work on bubbling stage excepts addEventListener with last argument true, which is the only way to catch the event on capturing stage.
  3. Bubbling/capturing can be stopped by event.cancelBubble=true (IE) or event.stopPropagation() for other browsers.
MarredCheese
  • 17,541
  • 8
  • 92
  • 91
gm2008
  • 4,245
  • 1
  • 36
  • 38
13

There's also the Event.eventPhase property which can tell you if the event is at target or comes from somewhere else, and it is fully supported by browsers.

Expanding on the already great snippet from the accepted answer, this is the output using the eventPhase property

var logElement = document.getElementById('log');

function log(msg) {
  if (logElement.innerHTML == "<p>No logs</p>")
    logElement.innerHTML = "";
  logElement.innerHTML += ('<p>' + msg + '</p>');
}

function humanizeEvent(eventPhase){
  switch(eventPhase){
    case 1: //Event.CAPTURING_PHASE
      return "Event is being propagated through the target's ancestor objects";
    case 2: //Event.AT_TARGET
      return "The event has arrived at the event's target";
    case 3: //Event.BUBBLING_PHASE
      return "The event is propagating back up through the target's ancestors in reverse order";
  }
}
function capture(e) {
  log('capture: ' + this.firstChild.nodeValue.trim() + "; " + 
  humanizeEvent(e.eventPhase));
}

function bubble(e) {
  log('bubble: ' + this.firstChild.nodeValue.trim() + "; " + 
  humanizeEvent(e.eventPhase));
}

var divs = document.getElementsByTagName('div');
for (var i = 0; i < divs.length; i++) {
  divs[i].addEventListener('click', capture, true);
  divs[i].addEventListener('click', bubble, false);
}
p {
  line-height: 0;
}

div {
  display:inline-block;
  padding: 5px;

  background: #fff;
  border: 1px solid #aaa;
  cursor: pointer;
}

div:hover {
  border: 1px solid #faa;
  background: #fdd;
}
<div>1
  <div>2
    <div>3
      <div>4
        <div>5</div>
      </div>
    </div>
  </div>
</div>
<button onclick="document.getElementById('log').innerHTML = '<p>No logs</p>';">Clear logs</button>
<section id="log"></section>
Adelin
  • 7,809
  • 5
  • 37
  • 65
  • [MDN's related doc on `composedPath`](https://developer.mozilla.org/en-US/docs/Web/API/Event/composedPath), and the shadow-boundary for a DOM element, is great additional context – New Alexandria Oct 17 '20 at 17:13
13

DOM Events describes 3 phases of event propagation: Capturing phase – the event goes down to the element. Target phase – the event reached the target element. Bubbling phase – the event bubbles up from the element.

enter image description here

vitoboski
  • 203
  • 2
  • 3
9

Bubbling

  Event propagate to the upto root element is **BUBBLING**.

Capturing

  Event propagate from body(root) element to eventTriggered Element is **CAPTURING**.
Kondal
  • 2,870
  • 5
  • 26
  • 40
3

When browser detects an event, it tries to find an event handler. This process has 3 phases. Let's say we have these elements

   <body>
      <div>
        <button>click</button>
      </div>
    </body>

1-Capture Phase

browser is going to take a look at the element that was just clicked. Then it will go to the top parent element which is body. if there is any click handle in body, the browser will call it. after checking the body element, it will look at the second top parent element which is div element. This process will repeat until the browser gets down to the button element at the very bottom. Once it sees the button element, Phase One- Capturing will be over. Most of the time we ignore this phase. This code ignores this phase

document.addEventListener('click',handleClick)

If you want to involve this phase, you have to write this

document.addEventListener('click',handleClick,true)

We need this phase when we need to detect a click outside the target. maybe we have a dropdown or a modal open and we want to close it if the user clicks on anywhere outside the modal or dropdown

2-Target Phase

the browser will look at the clicked element which is the Button and if the button has an event handler, it will call it.

3- Bubble Phase

Opposite to Capture Phase, in this phase, browser will start the process from the immediate parent element which is div element in this case and then it will visit the body element. This code will set up the event handler for the bubble phase

document.addEventListener('click',handleClick,false)
Yilmaz
  • 35,338
  • 10
  • 157
  • 202
2

As other said, bubbling and capturing describe in which order some nested elements receive a given event.

I wanted to point out that for the innermost element may appear something strange. Indeed, for some browser (e.g. on Mozilla Firefox), the order in which the event listeners are added does matter.

In the following example, capturing for div2 will be executed first than bubbling; while bubbling for div4 will be executed first than capturing.

function addClickListener (msg, num, type) {
  document.querySelector("#div" + num)
    .addEventListener("click", () => alert(msg + num), type);
}
bubble  = (num) => addClickListener("bubble ", num, false);
capture = (num) => addClickListener("capture ", num, true);

// first capture then bubble
capture(1);
capture(2);
bubble(2);
bubble(1);

// try reverse order
bubble(3);
bubble(4);
capture(4);
capture(3);
#div1, #div2, #div3, #div4 {
  border: solid 1px;
  padding: 3px;
  margin: 3px;
}
<div id="div1">
  div 1
  <div id="div2">
    div 2
  </div>
</div>
<div id="div3">
  div 3
  <div id="div4">
    div 4
  </div>
</div>

Remark: try running the snippet above with Mozilla Firefox.

logi-kal
  • 7,107
  • 6
  • 31
  • 43
  • The order of adding the event listeners **does not matter** try you own example if still not sure. – sasidhar Jun 25 '21 at 11:44
  • @sasidhar My example is self explanatory. Now if you click on the div #4 you get "*capture 3, bubble 4, capture 4, bubble 3*". If you reverse the order asserting `capture(3); capture(4); bubble(4); bubble(3);` and then click again on div #4 you'd get instead "*capture 3, capture 4, bubble 4, bubble 3*". This is a fact, even though I wouldn't be able to explain it. – logi-kal Jun 26 '21 at 14:46
  • 1
    tried your example in Edge and chrome, irrespective of order the result is always `capture(3); capture(4); bubble(4); bubble(3)'` – sasidhar Jun 30 '21 at 07:42
  • 1
    @sasidhar Sorry for the late reply. I use Firefox, anyway. – logi-kal Feb 11 '22 at 09:23
  • `Indeed, in this case the order in which the event listeners are added does matter. ` Since the major browsers do not behave in this way. We should stop relying on it => This sentence should be removed so that the readers do not get wrong information. – Rahul Jain Mar 25 '23 at 11:30
  • @RahulJain Mozilla Firefox _is_ a major browser. – logi-kal Mar 25 '23 at 14:13
  • @logi-kal I meant that bold `does matter` gives a wrong hint. It should be changed to "might matter depends on the browser". It is a browser-specific implementation, not like there is any rule or spec regarding this. – Rahul Jain Mar 25 '23 at 17:30
2

I made a small example, where you can experience "event-bubbling" live: https://codepen.io/abernier/pen/yKGJXK?editors=1010

enter image description here

Click any div, and you'll see the "click" event bubbling up!

$divs.forEach(($div) => $div.addEventListener("click", handleClick2));
abernier
  • 27,030
  • 20
  • 83
  • 114
0

These are event propagation process in javascript.

Event Bubbling: In this, the event is first captured and it is handled by the innermost element, where the event occurred, then it propagates through parent elements in the DOM hierarchy.

Event Capturing: In this case, the event is first captured and handled by the outermost element, then it propagates downward.

moaz ahmad
  • 174
  • 5