React Portals let you render components outside the main DOM tree — perfect for modals, tooltips, and dropdowns. But managing dozens of portals manually gets messy fast. Here's how to create a clean Portal Manager system in React without external libraries.
Why Use a Portal Manager?
Common use cases:
- Centralized control over all modals, tooltips, and popovers
- Dynamic stacking, layering, and closing logic
- Cleaner separation of UI layers
Step 1: Build a Portal Host
This component will be your centralized container for all portals:
// PortalHost.js
import { createContext, useContext, useState } from "react";
import { createPortal } from "react-dom";
const PortalContext = createContext(null);
export function PortalHost({ children }) {
const [portals, setPortals] = useState([]);
const mount = (node) => {
const id = Math.random().toString(36).substr(2, 9);
setPortals((prev) => [...prev, { id, node }]);
return id;
};
const unmount = (id) => {
setPortals((prev) => prev.filter((p) => p.id !== id));
};
return (
{children}
{portals.map(({ id, node }) =>
createPortal(node, document.body)
)}
);
}
export function usePortal() {
return useContext(PortalContext);
}
Step 2: Create a Hook for Dynamic Portals
We’ll build a simple hook to open and close portals:
// useDynamicPortal.js
import { usePortal } from "./PortalHost";
import { useEffect, useRef } from "react";
export function useDynamicPortal(content) {
const { mount, unmount } = usePortal();
const idRef = useRef(null);
useEffect(() => {
idRef.current = mount(content);
return () => unmount(idRef.current);
}, [content, mount, unmount]);
}
Step 3: Use It to Create a Modal Dynamically
Example of launching a modal when clicking a button:
// ExampleModal.js
import { useState } from "react";
import { useDynamicPortal } from "./useDynamicPortal";
function ModalContent({ onClose }) {
return (
I'm a modal!
);
}
function ExampleModal() {
const [open, setOpen] = useState(false);
if (open) {
useDynamicPortal( setOpen(false)} />);
}
return ;
}
export default ExampleModal;
Step 4: Wrap the App with the PortalHost
// App.js
import { PortalHost } from "./PortalHost";
import ExampleModal from "./ExampleModal";
function App() {
return (
);
}
export default App;
Pros and Cons
✅ Pros
- Centralized portal management
- No external libraries needed
- Clean separation of modal logic
⚠️ Cons
- More setup compared to a simple createPortal use
- Limited layering control without manual z-indexing
🚀 Alternatives
- React-Aria or Radix UI for more structured UI primitives
- Headless UI modals if you want battle-tested accessibility
Summary
When your React app grows, managing multiple popups, tooltips, and modals becomes chaotic. A Portal Manager brings clean order to the chaos, and this simple implementation is a solid foundation to customize even further for complex use cases.
For a much more extensive guide on getting the most out of React portals, check out my full 24-page PDF file on Gumroad. It's available for just $10:
Using React Portals Like a Pro.
If you found this useful, you can support me here: buymeacoffee.com/hexshift