DevPath · Learn to code ESPTEN

Modern React: Suspense, lazy, Portals and concurrency

Portals: rendering outside the DOM tree

The clipping problem

Imagine a modal defined inside a card with overflow: hidden and position: relative. Even though in React the modal is a "child" of the card, in the DOM it would be clipped by those styles and trapped in its stacking context (z-index). It's the classic case of a dropdown that gets cut off or a modal that appears behind another element.

React.createPortal

A Portal lets you render some children in another DOM node, outside the parent component's visual hierarchy, while still belonging to the React tree:

import { createPortal } from "react-dom";

function Modal({ children }) {
  return createPortal(
    <div className="modal-overlay">{children}</div>,
    document.body // mounted directly in <body>
  );
}

createPortal(children, domNode) takes what to render and where (an existing DOM node, typically document.body or a <div id="modal-root">).

The key: the DOM moves, not the React tree

Even though the modal appears in <body>, it's still a child of Modal in the React tree. This has two important consequences:

Typical use cases

Environment note: validating createPortal isn't reliable in the test runtime, so in this module we work with it conceptually.

Put this into practice

DevPath is a hands-on course: you read the theory here; in the app you put it into practice with exercises that really run, offline.

Start free in the app →
← Code splitting with React.lazy and SuspenseAdvanced refs and concurrency →