- Published on
Mastering React Portals: A Comprehensive Guide
- Authors
- Name
- Hieu Cao
Introduction
React Portals offer a way to render components outside of their parent DOM hierarchy. This feature is incredibly useful for building advanced UI patterns like modals, tooltips, and dropdowns that require a different DOM placement.
In this blog, we will explore what React Portals are, how they work, and when to use them in your projects.
What Are React Portals?
React Portals allow you to render a component into a DOM node outside of the root element where the React app is mounted. Despite rendering outside the DOM hierarchy, the component remains part of the React tree, preserving its context and state management.
Syntax:
ReactDOM.createPortal(child, container)
child
: The React component or element to render.container
: The DOM node where the component should be rendered.
Why Use React Portals?
- Modals and Dialogs: Prevents z-index and CSS overflow issues by rendering components outside of the main DOM structure.
- Tooltips and Popovers: Ensures the component appears above other content regardless of its parent hierarchy.
- Performance: Improves rendering efficiency by targeting specific DOM nodes.
How to Create a Portal
Let’s create a simple modal using React Portals.
Step 1: Set Up a DOM Node
Add a target DOM node in your HTML file (e.g., public/index.html
):
<div id="modal-root"></div>
Step 2: Implement the Modal Component
import React from 'react'
import ReactDOM from 'react-dom'
const Modal = ({ isOpen, onClose, children }) => {
if (!isOpen) return null
return ReactDOM.createPortal(
<div style={overlayStyles}>
<div style={modalStyles}>
<button onClick={onClose} style={closeButtonStyles}>
Close
</button>
{children}
</div>
</div>,
document.getElementById('modal-root')
)
}
const overlayStyles = {
position: 'fixed',
top: 0,
left: 0,
width: '100%',
height: '100%',
backgroundColor: 'rgba(0, 0, 0, 0.5)',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
}
const modalStyles = {
background: '#fff',
padding: '20px',
borderRadius: '8px',
maxWidth: '500px',
width: '100%',
boxShadow: '0 2px 10px rgba(0, 0, 0, 0.1)',
}
const closeButtonStyles = {
background: 'red',
color: '#fff',
border: 'none',
padding: '5px 10px',
cursor: 'pointer',
marginBottom: '10px',
}
export default Modal
Step 3: Use the Modal Component
import React, { useState } from 'react'
import Modal from './Modal'
const App = () => {
const [isModalOpen, setIsModalOpen] = useState(false)
return (
<div>
<h1>React Portals Example</h1>
<button onClick={() => setIsModalOpen(true)}>Open Modal</button>
<Modal isOpen={isModalOpen} onClose={() => setIsModalOpen(false)}>
<h2>This is a Portal Modal</h2>
</Modal>
</div>
)
}
export default App
Event Bubbling with Portals
One important note about React Portals is that event bubbling works as if the component is part of its original React tree, not where it is rendered in the DOM.
Example:
const Parent = () => {
return (
<div onClick={() => console.log('Parent Clicked')}>
Parent
<PortalChild />
</div>
)
}
const PortalChild = () => {
return ReactDOM.createPortal(
<button
onClick={(e) => {
e.stopPropagation()
console.log('Child Clicked')
}}
>
Click Me
</button>,
document.getElementById('modal-root')
)
}
In this example, clicking the button inside the portal logs "Child Clicked"
and stops the event from propagating to the parent.
When Not to Use Portals
While portals are powerful, they might not always be the right choice. Avoid using them when:
- Simple DOM Placement Works: If your component doesn't face z-index or CSS issues, use regular rendering.
- Performance Overhead: Portals introduce a small performance cost due to additional DOM manipulation.
Conclusion
React Portals are a versatile tool for building advanced UI patterns. By understanding their capabilities and limitations, you can create seamless user experiences in your React applications.
Happy coding!