Portals
Render children into a different part of the DOM, like a modal at the body root.
createPortal(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
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.
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.
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.
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