🎯 Understanding React Portals: When and How to Use Them
In many web applications, there comes a time when you need to render UI outside of the normal DOM hierarchy of a component. A common example is a modal dialog or a tooltip, which needs to appear visually above other content and often outside its parent container.
If you’ve ever faced layout issues like overlapping content, z-index conflicts, or weird positioning, chances are you’ve hit the limits of the default DOM tree rendering.
That’s where React Portals shine.
React Portals allow you to render a component’s subtree outside of its parent component’s DOM node—but still keep all the component’s state and event handling intact.
React provides a built-in API for this via:
import { createPortal } from 'react-dom'
The createPortal
method takes two arguments:
document.body
)Let’s take a look at a simple modal implementation using a portal:
import { createPortal } from 'react-dom'function Modal({title,content,handleClose,}: {title: stringcontent: stringhandleClose: () => void}) {return createPortal(<div className="modal"><h1>{title}</h1><p>{content}</p><button onClick={handleClose}>Close</button></div>,document.body,)}
And here’s how you’d use it in your App
:
function App() {const [showModal, setShowModal] = React.useState(false)return (<div><button onClick={() => setShowModal(true)}>Show Modal</button>{showModal && (<Modaltitle="My Modal"content="This is the content of the modal"handleClose={() => setShowModal(false)}/>)}</div>)}
📝 Notice how the modal content is rendered into document.body
, outside of the <div>
hierarchy of the App
component. Yet, it still behaves like it’s part of the same React component tree.
Some real-world scenarios where Portals are invaluable:
These elements often break out of their parents’ layout and need to be placed elsewhere in the DOM (like document.body
) to avoid being cut off or mispositioned.
Imagine you’re building a UI card component with a heart icon button. Some users report confusion, so you decide to add a tooltip that explains what the icon does.
Initially, you might write something like:
<div className="card"><button className="icon-button">❤️<Tooltip text="Add to favorites" /></button></div>
But you notice that the tooltip is being clipped or mispositioned because it’s being rendered inside the card’s DOM tree.
💥 This is a perfect use case for a Portal!
To fix this, render your Tooltip
using createPortal
:
import { createPortal } from 'react-dom'function Tooltip({ text, position }: { text: string; position: { top: number; left: number } }) {return createPortal(<div className="tooltip" style={{ top: position.top, left: position.left }}>{text}</div>,document.body,)}
You might use useLayoutEffect
to measure the icon’s position and pass the correct top
and left
props to the Tooltip
.
📎 Tip: Always check DevTools → Elements tab to verify where your tooltip/modal is being rendered.
For production-level tooltips and modals, it’s smart to use a well-tested library (like Radix UI
, Headless UI
, or React Aria
) that handles accessibility and edge cases for you.
But even those libraries use createPortal
under the hood—so understanding this concept will help you debug or extend their components when needed.
createPortal(ui, container)
is all you need to get started.z-index
and overflow
.🔮 Whether you’re building complex modals or floating tooltips, React Portals are your escape hatch from the DOM hierarchy. Master them, and you’ll unlock cleaner UI code and better UX.
Happy coding! 🚀
Quick Links
Legal Stuff
Social Media