# Event Bubbling, Event Capturing & Stop Propagation in JavaScript

Hello readers, before understanding **event bubbling** and **capturing** it is important to understand event propagation. If you are familiar with it skip to the event Bubbling section. 

## Event Propagation

> Event Propagation is a mechanism in which the event propagates or **travels** through the DOM (Document Object Model) tree of a webpage.

Event propagation occurs in three phases, this is called as Event Propagation Life Cycle:

![iEvent propagation life cycle](https://cdn.hashnode.com/res/hashnode/image/upload/v1651821897532/2NsHkajUR.png align="left")

1. **Capture Phase**: The event travels starting from the document object (window), through the HTML element towards the target element.
1. **Target Phase**: The event element reaches the target element which generated the event.
1. **Bubble Phase**: The event travels from the target element, through its parent towards the window object.

Now, as we have understood how an event flows in the DOM tree. Let's understand Event Bubbling and Capturing.

## Event Bubbling and Capturing

> Event bubbling and capturing describes the order in which event propagation occurs when a nested child element receives an event trigger and both the child and the parent element have event handlers registered to it.

### Setup
let us understand this with an example:

```html
  <body id="ancestor">
    ANCESTOR
    <ul id="parent">
      PARENT
      <li id="child">a</li>
      <li id="child">b</li>
      <li id="child">c</li>
    </ul>
    <script src="src/index.js"></script>
  </body>
```

This is the HTML code having elements in this order of nesting 
`body > ul > li` having corresponding id as `ancestor > parent > child`

```javascript
document.querySelector("#ancestor").addEventListener("click", () => {
  console.log("ancestor");
});

document.querySelector("#parent").addEventListener("click", () => {
  console.log("parent");
});

document.querySelector("#child").addEventListener("click", () => {
  console.log("child");
});
```

Now, each element is attached to an event listener which just logs its element id upon event trigger. for example, clicking on ancestor will log ```ancestor``` in the console.

This is the UI of the program, container a, b and c are the child elements.

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1651741185945/INCrPBHAC.png align="left")

We can check how the event propagates upon clicking on the child element.

![default event propagation (3).gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1651740761531/JNSXLt_EL.gif align="center")

As clear in the above animation, the event propagates from the child element to the ancestor element. ( child >> parent >> ancestor )

### Event Bubbling 

> When the event propagates from the child or target element to the window object such a mode of event propagation is called Event Bubbling.

Event bubbling is the default mode of event propagation. And thus in the example above for event bubbling, the order of propagation was:

#### On clicking child element:

1. first event listener of the child element receives the event.
1. second, the parent and 
1. third, the ancestor.

Thus, logs in the console for clicking on child element would be:
```html
child
parent
ancestor
```
#### On clicking parent element:

1. first event listener of the parent element receives the event and
1. second, the ancestor.


Thus, logs in the console for clicking on the parent element would be:
```html
parent
ancestor
```

Note: event bubble doesn't occur on every element, there are exceptions like focus, blur and scroll events where an event bubble is not observed.

### Syntax for Event handling (addEventListener)

Syntax: ```target.addEventListener(type, listener , useCapture);```

* type: A case-sensitive string representing an event type to listen for. In this example `'click'`
* listener:  An object that implements the Event interface when an event of the specified type occurs.
* useCapture (Optional): A Boolean denoting whether events of this type will be delivered to the registered listener before being delivered to any EventTarget beneath it in the DOM tree.
> If boolean not specified, useCapture defaults to false. i.e. Event Bubbling is enabled.

### Event Capturing

> When the event propagates from the document object to the target element such a mode of event propagation is called Event Capturing.

For observing event capturing, we need to specify the third argument of the `addEventListener` as a `true`.
so, the syntax would become: 
Syntax: ```target.addEventListener(type, listener , true);```


![event capturing.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1651743497848/8B7ILqJnO.gif align="left")

#### On clicking the child element:

1. first event listener of the ancestor element receives the event.
1. second, the parent and 
1. third, the child.

Thus, logs in the console for clicking on child element would be:
```html
ancestor 
parent
child
```
#### On clicking parent element:

1. first event listener of the ancestor element receives the event and
1. second, the parent.


Thus, logs in the console for clicking on the parent element would be:
```html
ancestor
parent
```

## Stop Propagation

> The **stopPropagation()** method of the **event interface** prevents further propagation of the current event during the event propagation.

for example: If we don't want the event to propagate to the ancestor in our example, we can call the stopPropagation method on the event we get in the callback() function of the addEventListener.

Code snippet for this case:
```javascript
  document.querySelector("#ancestor").addEventListener("click", () => {
  console.log("ancestor");
});

document.querySelector("#parent").addEventListener("click", (parentEvent) => {
  console.log("parent");
  parentEvent.stopPropagation();
});

document.querySelector("#child").addEventListener("click", () => {
  console.log("child");
});
```
In the parent element's event listener, we get an event interface, it is named as parentEvent here, upon which we called the stopPropagation method this will prohibit event propagation from the parent element implicating that the event has been completed successfully and no further propagation of event is required.

![stop propagation.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1651745228646/VcqIPWmIg.gif align="left")

As you noticed in the above example, when we click on the child element, first the event is received by the child element, and output is logged in the console but as soon as it encounters e.stopPropagation() in the parent event listener, it stops further propagation and does not bubble up in the DOM tree.

## Event Handling using Bubbling, Capturing and Stop Event Propagation

let's assume an example case, 
Consider we want to only trigger the parent element's event listener on click of the child element.

we can achieve this by using `useCapture` and `stopPropagation()` method.

Since the default case is the bubbling, on click of the child the first event received would be by a child element, but we don't want that.
So let's change the `useCapture` to `true` for each event listener to use Event Capturing.
Now, on clicking the child element the event received would be by the ancestor element, but we don't want this too.

So how can we get the event to be received by the parent element first?
The answer is to make the ancestor element listener to bubble, i.e., `useCapture` to `false`

Let's implement this in the code, our code snippet would look like this:
```javascript
document.querySelector("#ancestor").addEventListener(
  "click",
  () => {
    console.log("ancestor");
  },
  false
);

document.querySelector("#parent").addEventListener(
  "click",
  () => {
    console.log("parent");
  },
  true
);

document.querySelector("#child").addEventListener(
  "click",
  () => {
    console.log("child");
  },
  true
);
```

Now let's check the output:

![get parent event on child click.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1651746618001/77Wkw7LiH.gif align="left")

As seen above, we are making the parent listener receive the event first but we don't want the event to propagate from the parent element. This can be achieved by calling the stopPropagation method on the event received by the parent element's event listener.

So, our code snippet would look as follows:

```javascript
document.querySelector("#ancestor").addEventListener(
  "click",
  () => {
    console.log("ancestor");
  },
  false
);

document.querySelector("#parent").addEventListener(
  "click",
  (parentEvent) => {
    console.log("parent");
    parentEvent.stopPropagation();
  },
  true
);

document.querySelector("#child").addEventListener(
  "click",
  () => {
    console.log("child");
  },
  true
);
```

Final Output:

![only parent on child click.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1651747058884/KT3Azrw9v.gif align="center")

Thus, the desired output has been obtained. 

This was just a basic example of how we can handle events using the event bubbling, the event capturing and the stop propagation method.

Here's the code sandbox link to try on your own: 
[CodeSandbox Link](https://codesandbox.io/s/event-bubbling-and-event-capturing-j7ooyq)

## TLDR
* Event Propagation is the flow of events on the event trigger in the DOM tree. It has three phases:- ***Capture phase***, ***Target phase*** and ***Bubble phase***.
* In event bubbling the event bubbles up the DOM tree and in capturing the event trickles down the DOM tree.
* few events like focus and blur don't bubble up.
* event propagation could be changed from bubbling to capturing by setting the `useCapture` to `true` in the addEventListener.
    * Syntax: ```target.addEventListener(type, listener , true);```
* event propagation could be controlled by using `useCapture` and `stopPropagation()` method on event interface.

