Published on 4.8.2019
Modals are a common UI element in modern web applications. They allow you to display content in a layer that sits on top of the main application interface, and they’re typically used for things like alerts, confirmation dialogs, and forms.
In this post, we’ll explore React Portals — a powerful feature in React that allows you to render a component outside its parent component’s DOM hierarchy. We’ll specifically look at how to use React Portals to implement a modal in a functional component. We’ll also manage the modal’s state using the useState
hook.
Let’s jump in!
What are React Portals?
React Portals provide a first-class way to render a child component into a different part of the DOM, outside the parent component’s DOM hierarchy. This is particularly useful for managing modals, tooltips, dropdowns, or any UI element that needs to “escape” the normal flow of the component tree and be rendered somewhere else in the DOM.
In a typical React app, when you render components, they’re inserted into the DOM where they are called. With Portals, however, you can choose a different DOM node to render the child component into. This is especially useful for modals, which usually need to be displayed outside of the normal flow of the app (typically at the root level of your app or at a specific location).
Setting Up the Modal Component with React Portal
Let’s create a simple modal using React Portals.
We will:
- Use the
useState
hook to manage the modal’s open/close state. - Use the
ReactDOM.createPortal
method to render the modal outside the root div of the component.
Step 1: Create a Modal Component
First, we’ll create a basic modal component that will be rendered using a portal. It will accept two props: isOpen
(to control whether the modal is visible) and onClose
(to close the modal).
Modal.js
import React from 'react';
import ReactDOM from 'react-dom';
import './Modal.css';
const Modal = ({ isOpen, onClose, children }) => {
if (!isOpen) return null; // Don't render the modal if it's closed
return ReactDOM.createPortal(
<div className="modal-overlay">
<div className="modal-content">
<button className="close-button" onClick={onClose}>X</button>
<div>{children}</div>
</div>
</div>,
document.getElementById('modal-root') // Render the modal outside the component tree
);
};
export default Modal;
Explanation:
ReactDOM.createPortal
: This is the key part. We use it to render the modal outside the normal DOM hierarchy (specifically into a div with the id ofmodal-root
).- Conditional Rendering: The modal is only rendered if the
isOpen
prop istrue
. - Close Button: We include a simple close button that triggers the
onClose
function passed as a prop.
Step 2: Add CSS for the Modal
Now, let’s add some basic styles for the modal. This will make the modal overlay look more visually appealing and ensure that the content is properly positioned.
Modal.css
.modal-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 1000; /* Make sure the modal is on top of everything else */
}
.modal-content {
background: white;
padding: 20px;
border-radius: 5px;
width: 300px;
max-width: 100%;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}
.close-button {
background: #ff4d4f;
color: white;
border: none;
border-radius: 50%;
width: 30px;
height: 30px;
font-size: 18px;
position: absolute;
top: 10px;
right: 10px;
cursor: pointer;
}
.close-button:hover {
background: #e60000;
}
These styles will give us a basic centered modal with a semi-transparent background overlay, along with a close button in the top-right corner.
Step 3: Set Up the Modal in the App Component
Next, we’ll use the Modal
component in our App.js
. We will manage the modal’s open/close state using useState
and pass the necessary props to the modal.
App.js
import React, { useState } from 'react';
import Modal from './Modal';
import './App.css';
const App = () => {
const [isModalOpen, setIsModalOpen] = useState(false);
const openModal = () => setIsModalOpen(true);
const closeModal = () => setIsModalOpen(false);
return (
<div className="App">
<h1>React Portal Modal Example</h1>
<button onClick={openModal}>Open Modal</button>
{/* Modal Component */}
<Modal isOpen={isModalOpen} onClose={closeModal}>
<h2>This is a Modal!</h2>
<p>Click the button to close it.</p>
</Modal>
</div>
);
};
export default App;
Explanation:
useState
: TheisModalOpen
state controls whether the modal is open or closed.openModal
andcloseModal
: Functions to set the modal’s state to open or closed.Modal
Component: We passisOpen
andonClose
props to theModal
component to control its visibility and allow it to be closed when the user clicks the close button.
Step 4: Add a modal-root
Element
To render the modal outside the normal component hierarchy, we need to make sure there is a div
element with the id modal-root
in our HTML file.
In the public/index.html
file, add the following div
element just inside the <body>
tag:
public/index.html
<body>
<div id="root"></div> <!-- React app mounts here -->
<div id="modal-root"></div> <!-- Portal renders modals here -->
</body>
This modal-root
element will serve as the target for our React Portal to render the modal outside of the normal component hierarchy.
Step 5: Test the Modal
Now that everything is set up, run your app with npm start
, and you should see the following:
- A button that opens the modal when clicked.
- A modal that displays content when opened, with a close button in the top-right corner.
- Clicking the close button hides the modal.
Conclusion
In this post, we’ve learned how to use React Portals to manage modals in a React app. By rendering the modal outside of the parent component’s DOM hierarchy, React Portals give us a clean and flexible way to handle UI elements like modals that need to be rendered at a higher level in the DOM.
Key takeaways:
- React Portals allow us to render components outside of their parent hierarchy, making them ideal for modals, tooltips, and other UI overlays.
- We used
useState
to manage the modal’s open/close state. - We created a simple modal component and rendered it in a separate DOM node (
modal-root
) via a portal.
Now you’re ready to implement modals in your own React apps using React Portals!
Happy coding!