Detailed explanation
React portals let a component render its children into a DOM node outside its usual parent container while preserving their position in the React component tree. You create one with createPortal from react-dom, for example: return createPortal(<Modal />, document.body). Here, Modal appears under document.body in the browser’s DOM, but React still treats it as a child of the component that returned the portal. This distinction between DOM placement and React ownership is the central idea interviewers expect you to explain.
Portals are useful for modals, tooltips, dropdowns, and popovers whose visual placement should not be constrained by an ancestor’s layout. For example, a tooltip rendered inside a container with overflow: hidden may be clipped, and a modal inside a stacking context may remain behind other content even with a large z-index. Rendering into a suitable container outside those ancestors can avoid these restrictions. However, a portal does not automatically position an overlay or guarantee that it appears above everything; you still need appropriate CSS, coordinates, and stacking rules.
Under the hood, createPortal returns a React node describing the children and their target DOM container. React reconciles those children and manages their lifecycle as part of the existing React tree rather than creating a separate React root. Consequently, portalled components can read context from their React ancestors. React events also propagate through the React tree: clicking a button inside a portal can trigger an onClick handler on its React parent, even when that parent is not a DOM ancestor. Native DOM event propagation, by contrast, follows the actual DOM hierarchy.
For production use, the target container must already exist. A dedicated overlay container can make ownership and styling clearer than rendering directly into document.body. In server-rendered applications, browser globals such as document are unavailable on the server, so portal rendering needs a client-side strategy. Portals also provide no accessibility behaviour by themselves: a modal still needs an accessible name, appropriate dialog semantics, focus management, keyboard dismissal, and background interaction control. A strong interview answer connects the API to these practical responsibilities rather than presenting it as a complete modal solution.
Key points to remember
- Import createPortal from react-dom and pass children plus an existing DOM container.
- A portal changes DOM placement, not ownership in the React component tree.
- Context remains available, and React events propagate through React ancestors.
- Portals can escape ancestor clipping and stacking constraints, but still require suitable CSS.
- Accessibility, overlay positioning, and server-rendering compatibility require separate handling.
Common mistakes candidates make
- Claiming a portal creates a separate React root or loses access to parent context.
- Assuming React click handlers follow only the DOM hierarchy when portal content is clicked.
- Treating a portal as a complete modal implementation that automatically handles z-index, focus, and accessibility.
Likely follow-up questions
How do you prevent a click inside a portal from triggering a React ancestor’s click handler?
Call event.stopPropagation() in the relevant React click handler inside the portal. Alternatively, restructure the React tree or the ancestor’s handler so that it does not treat overlay interactions as ordinary content clicks.
How is createPortal different from createRoot?
createPortal places children in another DOM container while retaining their existing React ancestry and context. createRoot creates an independent React root, which does not automatically inherit context from another root.
What accessibility work is needed for a modal rendered through a portal?
Provide appropriate dialog semantics and an accessible name, move focus into the modal, and keep keyboard focus within it while open. Support Escape dismissal where appropriate, prevent background interaction, and restore focus to the triggering element when the modal closes.
Interview tip: Start with the DOM-versus-React-tree distinction, show the one-line API example, and explain one overlay use case plus the event-propagation caveat.
