Mastering React Portals: Render Components Outside the DOM Hierarchy
Last updated 2 months, 2 weeks ago | 119 views 75 5

Introduction: Why React Portals Matter
Ever tried building a modal, tooltip, or dropdown menu in React, only to battle with z-indexes, CSS overflows, or scroll clipping?
That's because these UI elements often need to break out of the normal DOM structure to render correctly.
React Portals solve this exact problem.
With React Portals, you can render components outside their parent’s DOM hierarchy, while still preserving React’s event bubbling and reactivity. This is perfect for modals, popovers, tooltips, and toast notifications.
What Are React Portals?
React Portals provide a way to render children into a DOM node that exists outside the DOM hierarchy of the parent component.
ReactDOM.createPortal(child, container)
-
child
: The React element you want to render -
container
: A real DOM node (usually outside the#root
div)
Introduced in React 16+, this gives you flexibility while keeping React's virtual DOM intact.
When to Use React Portals
Use Portals when:
-
You need to break out of parent styles (e.g.
overflow: hidden
) -
You want to render in a completely different part of the DOM
-
You’re building:
-
Modals
-
Tooltips
-
Dropdowns
-
Notifications/Toasts
-
Sidebars
-
How to Create a React Portal
1. Create a DOM Node in public/index.html
<!-- public/index.html -->
<body>
<div id="root"></div>
<div id="portal-root"></div> <!-- This is where we'll inject the portal -->
</body>
2. Use ReactDOM.createPortal()
// Modal.js
import ReactDOM from 'react-dom';
function Modal({ children }) {
return ReactDOM.createPortal(
<div className="modal-overlay">
<div className="modal-content">{children}</div>
</div>,
document.getElementById('portal-root') // Inject here
);
}
export default Modal;
3. Use the Modal in a Component
import Modal from './Modal';
import { useState } from 'react';
function App() {
const [isOpen, setIsOpen] = useState(false);
return (
<div>
<h1>Main App Content</h1>
<button onClick={() => setIsOpen(true)}>Open Modal</button>
{isOpen && (
<Modal>
<h2>This is a Portal Modal</h2>
<button onClick={() => setIsOpen(false)}>Close</button>
</Modal>
)}
</div>
);
}
✅ The modal renders outside the main #root
, but React still manages its lifecycle and event bubbling.
Complete Working Code Example
<!-- public/index.html -->
<body>
<div id="root"></div>
<div id="portal-root"></div>
</body>
// Modal.js
import ReactDOM from 'react-dom';
function Modal({ children }) {
return ReactDOM.createPortal(
<div style={modalStyles.overlay}>
<div style={modalStyles.content}>{children}</div>
</div>,
document.getElementById('portal-root')
);
}
const modalStyles = {
overlay: {
position: 'fixed',
top: 0,
left: 0,
right: 0,
bottom: 0,
background: 'rgba(0,0,0,0.5)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
},
content: {
background: '#fff',
padding: '20px',
borderRadius: '4px',
minWidth: '300px',
},
};
export default Modal;
// App.js
import { useState } from 'react';
import Modal from './Modal';
function App() {
const [isOpen, setIsOpen] = useState(false);
return (
<div style={{ padding: '50px' }}>
<h1>React Portals Example</h1>
<button onClick={() => setIsOpen(true)}>Show Modal</button>
{isOpen && (
<Modal>
<h2>Portal Modal</h2>
<p>This modal is rendered outside the root DOM tree!</p>
<button onClick={() => setIsOpen(false)}>Close</button>
</Modal>
)}
</div>
);
}
export default App;
Benefits of Using React Portals
Feature | React Portal Benefit |
---|---|
DOM flexibility | Render in different parts of DOM |
Avoids CSS issues | Bypass overflow: hidden or z-index clashes |
Keeps React logic intact | Still uses React's lifecycle, context, and events |
Easier to manage overlays | No need for separate JS-driven appendChild logic |
Tips & Common Pitfalls
✅ Best Practices
-
Add
#portal-root
near the root DOM structure (but outside#root
) -
Use portals for UI elements that must overlay other elements
-
Make sure your modal supports focus trapping and keyboard accessibility
-
Clean up event listeners or timers when the portal unmounts
❌ Common Mistakes
-
Forgetting to add the portal container (
#portal-root
) inindex.html
-
Using portals unnecessarily for components that don’t need DOM separation
-
Breaking event flow assumptions (e.g., mouse events outside the overlay)
Comparison: React Portals vs Normal DOM Mounting
Feature | Standard React Rendering | React Portal |
---|---|---|
Renders inside parent DOM | ✅ Yes | ❌ No (outside hierarchy) |
Avoids layout/CSS conflicts | ❌ No | ✅ Yes |
Keeps React reactivity | ✅ Yes | ✅ Yes |
Suitable for overlays/modals | ❌ Harder | ✅ Best choice |
Conclusion: Build Flexible UIs with React Portals
React Portals are a must-have tool when building overlays, modals, and floating UI elements that break out of the typical DOM structure. With just a few lines of code, you get powerful layout control without sacrificing React’s state and lifecycle features.
Key Takeaways
-
Use
ReactDOM.createPortal(child, container)
to render outside parent hierarchy -
Portals are ideal for modals, tooltips, and other overlays
-
Keep your DOM clean and your UI flexible with this powerful pattern