Portal
Rendering a child somewhere else in the DOM, usually under document.body, while it still behaves like part of its original component tree.
See it
What it is
A portal renders a child into a different DOM node, often a layer under document.body, while keeping it in the same React tree. Context still reaches it, state still belongs to the parent, and React events still bubble through React ancestors. Only its physical place in the DOM changes. Vue ships the same idea under the name Teleport.
Reach for createPortal when a modal, tooltip, menu, or toast must escape an ancestor's overflow clipping or stacking context. The overlay can then use position: fixed against the viewport instead of fighting the layout that triggered it.
Gotcha: a portal solves placement, not accessibility. A modal still needs a label, focus trapping, Escape handling, background inertness, and focus restoration. CSS inheritance now follows the portal's DOM location, and a click inside it can trigger a React ancestor's handler even though that ancestor is elsewhere in the DOM.
Ask AI for it
Build this modal with React DOM createPortal and render it into a dedicated #modal-root beside the app root. Guard access to document during server rendering, use position: fixed for the backdrop, give the panel role='dialog', aria-modal='true', and an accessible name, trap focus inside it, close on Escape, mark the background inert while open, and restore focus to the trigger on close. Stop propagation only if the surrounding React tree has a documented click handler that must not receive portal events.