Event bubbling and handling in React JS and DOM
Tags: react, webdev, javascript
Published: 2023-10-31 16:50:54

---
title: Event bubbling and handling in React JS and DOM
published: true
date: 2023-10-30 14:25:37 UTC
tags: react,webdevelopment,javascript
canonical_url: https://medium.com/@for.mvpetrov/event-bubbling-and-handling-in-react-js-and-dom-1a586df2a093
---

![bubble art](https://cdn-images-1.medium.com/max/1024/1*2uc7bXlzsfNgbQ8IjKjinQ.jpeg)

Event bubbling is a concept in the Document Object Model (DOM) of JavaScript. When a user clicks on an element, for example, a **<div />** , it first runs the click listener on that **<div />** , then on its parent, then all the way up on other ancestors until it reaches the window. The event pops up as a bubble from the clicked element to the top level.

Let’s add a React.

```typescript
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);
```

And render 3 nested div’s as React components.

![Rendered div blocks](https://cdn-images-1.medium.com/max/219/1*EzcoOKxmnJ2YW-CHF9rVdQ.png)

React uses a synthetic event wrapper instead of the native browser event to handle events in the DOM. It subscribes to the root element events only. When clicking **div.level3,** DOM click listeners are called in the following order: **div.level3** → **div.level2** → **div.level1** → **div#root**. React is subscribed to **div#root** and receives click event with **target** set to **div.level3.** It generates synthetic event and calls **onClick** handlers at the same bubbling way **div.level3** → **div.level2** → **div.level1**. We are still in DOM bubbling phase and the next step is to call listeners on **document** and  **window**.

![Event bubbling scheme](https://cdn-images-1.medium.com/max/376/1*t1UISJATjxGLMNILLFP0OQ.png)

React handlers are called after all **div#root** children handled DOM events. That’s why calling **stopPropagation()** inside React handlers only prevents that component’s parents from calling onClick handlers.

```typescript
function TestComponent() {
  const ref = React.useRef();
  React.useEffect(() => {
    ref.current.addEventListener('click', (e) => {
      console.log('Called first');
    });
  }, []);

  return <div onClick={(e) => {
    console.log('Called last');
    e.stopPropagation();
  }} />;
}
```

React doesn’t receive event if any of its components called DOM **stopPropagation().**

```typescript
function TestComponent() {
  const ref = React.useRef();
  React.useEffect(() => {
    ref.current.addEventListener('click', (e) => {
      console.log('Called first');
      e.stopPropagation();
    });
  }, []);

  return <div onClick={(e) => {
    console.log('Never called');
  }} />;
}
```

![React bubbles art](https://cdn-images-1.medium.com/max/1024/1*I1vM7swN2yHdcT5fz8E08A.jpeg)

Why should one use DOM listeners, if React is a powerful tool for all the tricks with events?

**1. Vanilla JS libraries with React wrappers**

A lot of libraries created with Vanilla JS are available with React wrappers. React developer should know about event bubbling to interact properly with these libraries.

**2. Click-outside task**

One of the common tasks is click outside tracking for some popup menu to close it (just subscribe to document click event and check that your component doesn’t contain event.target, example of implementation in [ahooks](https://github.com/alibaba/hooks/blob/master/packages/hooks/src/useClickAway/index.ts) library)

**3. Call preventDefault() for passive handlers**

Some listeners of React are [passive](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#passive). That’s why implementing custom component behavior for wheel event could be a problem. You can write your logic to handler, but you can’t prevent default scrolling. **addEventListener** solves this problem.

What was your reason for using **addEventListener** with React?

And yeah, the picture would not be complete without mentioning the **DOM** capture phase. But so far I have not had any tasks where I needed to use it with React.

![Bubbling scheme with capture phase](https://cdn-images-1.medium.com/max/667/1*_6HTHGl0hu2hDKSCUs7-5Q.png)

The repository with example is available [here](https://github.com/mvp-v/react-event-bubbling). It just logs out all phases of click event.

![Example console output](https://cdn-images-1.medium.com/max/397/1*0pB8EBfV2HQLG7cEMfs9qQ.png)

[Link for the CodeSandbox](https://codesandbox.io/s/gifted-chebyshev-n3xsps?file=/src/App.js) to play with. Just set stopPropagation prop for any Block component.

![CodeSandbox example screenshot](https://cdn-images-1.medium.com/max/1024/1*q0kFQPjDtG2LffPM3iyynw.png)