React Portals Explained

Hero image for React Portals Explained. Image by Thor Alvis.
Hero image for 'React Portals Explained.' Image by Thor Alvis.

Some React UI problems are not really about React at all. They are about the DOM.

Modals, overlays, tooltips, and dropdown panels often want to appear visually outside the normal layout hierarchy. If we render them exactly where the component sits in the tree, they can end up clipped by overflow, trapped inside stacking contexts, or awkwardly layered under other content.

That is why React Portals exist.

They let us render part of a React subtree into a different place in the DOM while still keeping it inside the same React application.


A Portal Changes DOM Placement, Not React Ownership

This is the most important thing to understand.

With a portal, the element appears elsewhere in the DOM, but it still belongs to the same React tree logically.

That means state, props, and event behaviour still connect back to the component that created it.

In React, that looks like this:

import ReactDOM from 'react-dom';const Modal = ({ children }: { children: React.ReactNode }): JSX.Element =>  ReactDOM.createPortal(    <div className="modal">{children}</div>,    document.getElementById('modal-root') as HTMLElement,  );

The modal content might be rendered under a toplevel #modalroot element near the end of body, even if the component using it lives much deeper in the interface.


Why This Helps with Overlays

Overlays often need freedom from their parent's layout constraints.

If a modal is rendered inside a container with:

  • overflow: hidden
  • complex positioning
  • a lower stacking context

then keeping it in that exact DOM branch can make the UI harder to layer correctly.

Portals let the overlay escape that physical DOM location without forcing the whole state model to move somewhere else.


Modals are the Classic Use Case

Imagine a page component rendering a button that opens a dialog:

const ProductPage = (): JSX.Element => {  const [isOpen, setIsOpen] = useState(false);  return (    <>      <button onClick={() => setIsOpen(true)}>Open size guide</button>      {isOpen && (        <Modal>          <button onClick={() => setIsOpen(false)}>Close</button>        </Modal>      )}    </>  );};

The open state can still live with the page component, which is where the interaction belongs. The modal itself can render elsewhere in the DOM so the layering stays sane.

The matching DOM target is usually simple as well:

<body>  <div id="__next"></div>  <div id="modal-root"></div></body>

That is often all a portal needs. The React ownership stays with the page component, whilst the final DOM placement moves to a toplevel node better suited to overlays.


Event Bubbling Still Follows the React Tree

This is one of the more interesting details.

Even though the portal content is rendered elsewhere in the DOM, events still bubble through the React component tree rather than becoming disconnected from it.

That means a parent component can still handle events from content rendered in a portal.

This behaviour often surprises people at first, but it is part of what makes portals feel integrated rather than bolted on.


Portals Solve Placement Problems, Not All Modal Problems

This is a good warning to keep in mind.

Rendering a dialog through a portal does not automatically make it accessible or wellbehaved.

You still need to think about:

  • keyboard focus
  • focus return when closing
  • escapekey handling
  • background interaction
  • screenreader semantics

The portal helps with DOM placement. It does not finish the component design for you.


Tooltips and Dropdowns Can Benefit Too

Modals are the obvious example, but the same principle applies to other floating UI:

  • tooltip layers
  • context menus
  • autocomplete panels
  • dropdown menus

Any UI that needs to escape clipping or stacking problems may benefit from portal rendering.

That said, not every dropdown needs a portal. If ordinary DOM placement works cleanly, forcing a portal in too early can make the code more complex than necessary.


Accessibility Still Needs Deliberate Work

This matters enough to say twice in different words.

The portal moves where the node is rendered, but it does not tell assistive technology what the thing is supposed to be.

A real modal still needs a good accessibility story:

  • appropriate dialog semantics
  • trapped focus while open
  • inert or hidden background content where necessary
  • a reliable closing mechanism

Without those pieces, a portaldriven modal can still be a poor modal.


It Helps to Separate Logical Tree from Physical Tree

That is the mental model that makes portals click.

The React tree represents ownership, state, and component relationships.

The DOM tree represents actual document placement.

Most of the time, those structures line up closely enough that we do not think about the distinction. Portals are one of the places where React lets us separate them deliberately.


When Not to Use a Portal

If a component does not have a real placement problem, a portal may be unnecessary.

For example, wrapping every floating box in a portal by default can create extra indirection without solving a real issue. The right test is practical:

Is the UI genuinely fighting layout, overflow, or stacking in its current location?

If yes, a portal may help.

If not, keeping the markup in its ordinary place is often simpler.


Portals are About Escaping DOM Constraints Without Breaking Component Structure

That is why they are useful.

Before portals, developers often had to choose between:

  • awkward DOM nesting
  • moving state ownership to an unnatural place

Portals reduce that tension. The parent component can still own the interaction, while the DOM output can move to a place better suited to floating UI.


This is a Structural Feature, Not a Visual Trick

Seen properly, portals are not just a hack for modals. They are a way of saying:

"This UI belongs here in the React tree, but it needs to appear elsewhere in the DOM."

Once you understand that sentence, the feature becomes very intuitive.

It is one of React's cleaner answers to a real browser constraint, and it is most valuable when used exactly where the DOM would otherwise get in the way.


Categories:

  1. Development
  2. Front‑End Development
  3. Guides
  4. JavaScript
  5. React