Modal dialogs
A dialog must visually escape an ancestor with clipping, stacking, or positioning constraints.
React 19+ · Function
createPortal renders React children into a different part of the DOM while keeping them in the rendering component's React tree. It is commonly used for modals, tooltips, and other UI that must escape a container.
Call createPortal with renderable children and an existing DOM node, then return the resulting React node from JSX or a component. React places the children in that node's DOM location, while the portal remains a child of the component in the React tree for context and event behavior.
createPortal(children, domNode, key?)| Name | Type | Description |
|---|---|---|
children | ReactNode | Anything React can render, such as JSX, a Fragment, a string, a number, or an array of these. |
domNode | Element | An already existing DOM node where the children will be placed. |
key | string | number | Optional unique string or number used as the portal key. |
A React node that can be included in JSX or returned from a React component; React places its children inside the specified DOM node.
import { createPortal } from 'react-dom';
export function Modal({ open, children, onClose }) {
if (!open) return null;
return createPortal(
<div role="dialog" aria-modal="true">
{children}
<button onClick={onClose}>Close</button>
</div>,
document.body
);
}This component keeps the modal in React's tree while placing its DOM under document.body.
A dialog must visually escape an ancestor with clipping, stacking, or positioning constraints.
Transient UI should render above the page or outside a constrained container.
An overlay needs a body-level DOM mount while retaining parent component state and context.
It renders children into a different DOM location while preserving their position in the React tree. Therefore, React context and event propagation follow the component hierarchy rather than the DOM hierarchy.
Follow-up: What happens if the destination changes? React recreates the portal content when a different DOM node is supplied during an update.
The children argument accepts anything React can render, including JSX, fragments, strings, numbers, and arrays of renderable values. The destination must be an already existing DOM node.
Follow-up: How would you make a portal destination stable? Resolve a fixed node, such as document.body or a persistent element returned by getElementById, and avoid replacing it between renders.
createPortal returns a React node. Include that node in JSX or return it from a component; React then inserts the supplied children into the specified DOM node.
Follow-up: Can a portal be used during server rendering? No: the documentation states that portals are not currently supported on the server, so the call must be client-only.
createRootReact DOM APIscreateContextuseContext