Portals

Render children into a different part of the DOM, like a modal at the body root.

SyntaxcreatePortal(children, document.body)

A portal renders children into a DOM node outside the parent component's hierarchy, while keeping them in the React tree for events and state. This is ideal for modals, tooltips and toasts that must escape a container's overflow or z-index.

How it works

Call createPortal(children, domNode) from react-dom. The JSX still belongs to your component — context and event bubbling work as if it were in place.

Example

Example · javascript
import { createPortal } from 'react-dom';

function Modal({ children, onClose }) {
  return createPortal(
    <div className="overlay" onClick={onClose}>
      <div className="modal">{children}</div>
    </div>,
    document.body
  );
}

function App() {
  return (
    <Modal onClose={() => {}}>
      <p>I render at document.body!</p>
    </Modal>
  );
}

When to use it

  • A modal dialog renders via createPortal into document.body so it escapes a parent container's overflow: hidden and always appears above all other content.
  • A tooltip component uses a portal to render near the cursor at the document root, preventing it from being clipped by a scrollable table container.
  • A toast notification system renders alerts into a fixed position element outside the app root so they overlay any stacking context without z-index conflicts.

More examples

Modal via createPortal

Renders the modal at document.body via createPortal so it escapes overflow/stacking context of its parent container.

Example · jsx
import { createPortal } from 'react-dom';

function Modal({ isOpen, onClose, children }) {
  if (!isOpen) return null;
  return createPortal(
    <div className="modal-backdrop" onClick={onClose}>
      <div className="modal" onClick={e => e.stopPropagation()}>
        {children}
        <button onClick={onClose}>Close</button>
      </div>
    </div>,
    document.body
  );
}

Toast notification portal

Renders toast alerts into a dedicated root element outside the main app so z-index management is trivial.

Example · jsx
import { createPortal } from 'react-dom';

const toastRoot = document.getElementById('toast-root');

function Toast({ message }) {
  return createPortal(
    <div className="toast" role="alert" aria-live="polite">
      {message}
    </div>,
    toastRoot
  );
}

Portal with forwarded ref

Combines createPortal with forwardRef so the parent can measure or focus the portalled dropdown list.

Example · jsx
import { createPortal, forwardRef } from 'react';

const Dropdown = forwardRef(function Dropdown({ items, style }, ref) {
  return createPortal(
    <ul ref={ref} className="dropdown" style={style}>
      {items.map(item => <li key={item.id}>{item.label}</li>)}
    </ul>,
    document.body
  );
});

export default Dropdown;

Discussion

  • Be the first to comment on this lesson.