Portals
HardPortals render children into a DOM node outside the parent component's DOM hierarchy using createPortal. They are essential for modals, tooltips, and dropdowns that must visually escape overflow or z-index stacking contexts while maintaining React tree behavior like event bubbling and context access.
Interactive Visualization
Key Points
- createPortal(children, domNode) renders into any DOM node
- Portal children escape overflow:hidden and z-index stacking contexts
- Events still bubble through the React tree, not the DOM tree
- Context is still accessible from the React tree position
- Common for modals, tooltips, toasts, and dropdown menus
- The target DOM node must exist before the portal renders
Code Examples
Modal Portal
import { createPortal } from 'react-dom' import { useEffect, useRef, type ReactNode } from 'react' interface ModalProps { children: ReactNode isOpen: boolean onClose: () => void } function Modal({ children, isOpen, onClose }: ModalProps) { const overlayRef = useRef<HTMLDivElement>(null) useEffect(() => { if (!isOpen) return const handleEscape = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose() } document.addEventListener('keydown', handleEscape) return () => document.removeEventListener('keydown', handleEscape) }, [isOpen, onClose]) if (!isOpen) return null return createPortal( <div ref={overlayRef} onClick={(e) => { if (e.target === overlayRef.current) onClose() }} style={{ position: 'fixed', inset: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', background: 'rgba(0,0,0,0.5)', }} > <div>{children}</div> </div>, document.body ) } function App() { const [showModal, setShowModal] = useState(false) return ( <div style={{ overflow: 'hidden' }}> <button onClick={() => setShowModal(true)}>Open Modal</button> <Modal isOpen={showModal} onClose={() => setShowModal(false)}> <h2>Modal Title</h2> <p>This escapes overflow:hidden</p> </Modal> </div> ) }
The modal renders into document.body via a portal, escaping any overflow or stacking context from its parent hierarchy
Common Mistakes
- Forgetting that the portal target DOM node must exist before rendering
- Not handling keyboard events like Escape for accessibility
- Assuming portal events follow the DOM hierarchy instead of the React tree
Interview Tips
- Explain that events bubble through the React tree, not the DOM tree, for portals
- Know the use cases: modals, tooltips, toasts, anything that needs to escape stacking contexts
- Discuss accessibility requirements for portal-based modals like focus trapping