React’s createPortal Changed How I Build Modals (Forever)

React’s createPortal Changed How I Build Modals (Forever)

AI-generated illustration of a glowing React logo symbolizing modern web application development
AI-generated illustration of a glowing React logo symbolizing modern web application development.

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.

Also See

Comments