React’s createPortal
Changed How I Build Modals (Forever)
You know that moment when a feature clicks so hard, you wonder how you ever
did it the old way? For me, that was createPortal
. One line of
code. Zero layout bugs. Infinite flexibility.
In this post, I’ll show you why React portals are the secret weapon for rendering outside the DOM tree—and why they’re your new best friend for modals, tooltips, dropdowns, and more.
What Is createPortal
?
Introduced in React 16, ReactDOM.createPortal
lets you render a
child component into a DOM node that exists outside the
parent component’s hierarchy.
Think of it as saying: “Hey React, please render this component somewhere else in the DOM—but keep all the state and reactivity intact.”
Syntax:
ReactDOM.createPortal(child, container)
Before Portals: Painful DOM Hacks
Let me paint you a picture. I had a modal. It worked fine—until it didn’t. Z-index issues. Scroll traps. Sibling DOM bleeding. You name it.
My solution? Ugly hacks like appending modals to
document.body
and manually managing event listeners.
document.body.appendChild(modalElement)
Sound familiar? Portals were the breath of fresh air I desperately needed.
The “Aha!” Moment
One day, I discovered createPortal
. I refactored my modal into
this:
ReactDOM.createPortal(
<ModalContent />,
document.getElementById("modal-root")
)
And just like that—no scroll issues, no z-index drama. The modal rendered beautifully outside the main app DOM, while still behaving like it lived inside React.
Why Portals Are a Game-Changer
- Fixes z-index and overflow issues instantly
- Keeps React state and event bubbling intact
- Perfect for modals, dropdowns, and popovers
- No more DOM hacks or workarounds
Copy This Real-World Modal Setup
App.jsx:
import Modal from "./Modal";
import { useState } from "react";
function App() {
const [open, setOpen] = useState(false);
return (
<>
<button onClick={() => setOpen(true)}>Open Modal</button>
{open && <Modal onClose={() => setOpen(false)} />}
</>
);
}
Modal.jsx:
import { createPortal } from "react-dom";
export default function Modal({ onClose }) {
return createPortal(
<div className="modal-backdrop">
<div className="modal-content">
<p>This is a modal!</p>
<button onClick={onClose}>Close</button>
</div>
</div>,
document.getElementById("modal-root")
);
}
Pro Tips to Use It Like a Senior Dev
-
Always create a dedicated
<div id="modal-root">
in your HTML - Use
useEffect
to clean up listeners if needed - Portals still bubble events through React—no extra wiring
- Works seamlessly with CSS frameworks like Tailwind
When Should You Use createPortal
?
- Modals and dialogs
- Dropdown menus that escape layout bounds
- Tooltips and popovers
- Toasts and notifications
Go Beyond: Advanced Portal Magic
- Animate your portals with React Transition Group
- Combine with context providers for seamless data access
- Use a PortalManager component to manage z-index stacking
Conclusion
If you’ve ever wrestled with rendering components outside their container—createPortal is the tool you didn’t know you needed.
Cleaner DOM. Cleaner code. Better UX. What’s not to love?
Your Turn
Ready to try it yourself? I’ve got a working example right here: GitHub: github.com/karpitonys-stash/example-createPortal
Clone it, test it, and say goodbye to DOM hacks forever. Your modals (and your users) will thank you.
Comments
Post a Comment