React Portals: Managing Modals in Functional Components

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 of modal-root).
  • Conditional Rendering: The modal is only rendered if the isOpen prop is true.
  • 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: The isModalOpen state controls whether the modal is open or closed.
  • openModal and closeModal: Functions to set the modal’s state to open or closed.
  • Modal Component: We pass isOpen and onClose props to the Modal 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:

  1. A button that opens the modal when clicked.
  2. A modal that displays content when opened, with a close button in the top-right corner.
  3. 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!

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *