How to Implement React Portals in React
React Portals provide a powerful way to render child components into a DOM node that exists outside the DOM hierarchy of the parent component. This article explains the core concept of React Portals, why they are essential for UI elements like modals, tooltips, and dropdowns, and provides a clear, step-by-step guide on how to implement them in your React applications.
Why Use React Portals?
In a standard React application, components render within the DOM
hierarchy of their parent components. However, this can cause visual
bugs when dealing with CSS properties like z-index,
overflow: hidden, or position: absolute. For
example, a modal nested deep inside a container with
overflow: hidden might get clipped.
React Portals solve this by allowing you to render a component
visually on top of everything else (like at the end of the
<body> tag) while maintaining its position in the
React component tree. This ensures the component still has access to
React context, state, and props.
Step 1: Add a Target DOM Node
First, you need to define where the portal should render in your HTML
structure. Open your public/index.html file (or your main
HTML entry file) and add a new placeholder div next to the
main application root.
<body>
<!-- The main React application -->
<div id="root"></div>
<!-- The target element for your portal -->
<div id="portal-root"></div>
</body>Step 2: Create the Portal Component
To create a portal, use the createPortal function from
the react-dom package. This function takes two arguments:
the React elements to render (the children) and the DOM element where
those elements should be mounted.
Create a reusable Portal component:
import { createPortal } from 'react-dom';
const Portal = ({ children }) => {
// Select the target DOM node created in Step 1
const portalRoot = document.getElementById('portal-root');
// If the target element doesn't exist, return null
if (!portalRoot) return null;
// Render the children inside the target DOM node
return createPortal(children, portalRoot);
};
export default Portal;Step 3: Implement the Portal in a Component
Now you can use the Portal component to overlay elements
like modals. Here is an example of a modal component that uses the
portal to render outside the main application DOM structure.
import React, { useState } from 'react';
import Portal from './Portal';
const Modal = ({ isOpen, onClose }) => {
if (!isOpen) return null;
return (
<Portal>
<div className="modal-overlay" style={overlayStyles}>
<div className="modal-content" style={modalStyles}>
<h2>Modal Title</h2>
<p>This modal is rendered outside the main app root!</p>
<button onClick={onClose}>Close Modal</button>
</div>
</div>
</Portal>
);
};
// Simple inline styles for demonstration
const overlayStyles = {
position: 'fixed',
top: 0,
left: 0,
right: 0,
bottom: 0,
backgroundColor: 'rgba(0, 0, 0, 0.7)',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
zIndex: 1000,
};
const modalStyles = {
background: 'white',
padding: '20px',
borderRadius: '8px',
boxShadow: '0 2px 10px rgba(0, 0, 0, 0.1)',
};
export default Modal;Step 4: Use the Modal in Your Application
You can now toggle and render the modal from any parent component without worrying about parent container CSS clipping the modal container.
import React, { useState } from 'react';
import Modal from './Modal';
function App() {
const [isModalOpen, setIsModalOpen] = useState(false);
return (
<div style={{ padding: '20px', overflow: 'hidden' }}>
<h1>My Application</h1>
<button onClick={() => setIsModalOpen(true)}>Open Modal</button>
{/* Even inside a container with overflow hidden, this renders correctly */}
<Modal isOpen={isModalOpen} onClose={() => setIsModalOpen(false)} />
</div>
);
}
export default App;Key Considerations
- Event Bubbling: Even though a portal renders outside the parent DOM node, it behaves like a normal React child in terms of event propagation. An event fired from inside a portal will still bubble up to ancestors in the React tree, which is highly useful for event delegation.
- Accessibility: Ensure that keyboard focus and screen reader navigation are managed properly when using portals, as screen readers read the DOM hierarchy rather than the React component tree.