React / React Portal / Event Bubbling
Home /React /React Portal /Event Bubbling

Event Bubbling

Event Bubbling Through Portals

This is one of the most important and often misunderstood aspects of Portals.

Rule: Events fired inside a Portal bubble up through the React component tree,
NOT through the DOM tree. This is by design.

Example


import { createPortal } from 'react-dom';

function Parent() {
  function handleClick() {
    console.log('Parent caught the click!');
    // This fires even though the button is inside a Portal
    // mounted outside Parent's DOM node
  }

  return (
    <div onClick={handleClick}>
      <p>I am the parent.</p>
      {createPortal(
        <button>Click me (I'm in a Portal)</button>,
        document.getElementById('portal-root')
      )}
    </div>
  );
}

Clicking the button triggers handleClick in Parent — even though the button’s DOM
node is inside #portal-root, far from div onClick in the physical DOM.

React Tree vs DOM Tree Bubbling Comparison

Aspect React Component Tree Real DOM Tree
Events bubble through Yes (Portal’s logical parent) No (Portal’s DOM parent is different)
Context available Yes (inherits from logical parent) N/A
React state inheritance Yes N/A
CSS inheritance No (follows physical DOM parent) Yes (follows physical DOM parent)

Stopping Portal Event Bubbling


// Prevent events from Portal reaching the React parent
{createPortal(
  <div onClick={(e) => e.stopPropagation()}>
    {/* Content inside won't bubble to Portal's React parent */}
    <button>Click</button>
  </div>,
  document.body
)}