DEV Community

Cover image for 🔧 Build a complete Modal Component with React Hooks 🌈
Victor de la Fouchardière
Victor de la Fouchardière

Posted on • Updated on

🔧 Build a complete Modal Component with React Hooks 🌈

Hi guys !

Last week, we talked about 5 Customs React Hooks ! Many of you have shared this article. So this week, let's continue with React and the implementation of a Modal component without installing any packages!

React Modal demo

A Modal component from scratch

Before starting, here are the elements we will use during this tutorial:

  • React Hooks
  • Portals from ReactDOM
  • A little bit of CSS

Let's start with our modal.jsx (or modal.js) file !

Our component:

Let's start with the basics: the creation of our function component. The goal is to include any content to the modal and to manage the opening and closing of the component.

React Modal Hooks

Secondly, what we want is a modal that is independent of our application. We don't want to have any z-index concerns in css or any overflow concerns. So let's insert this component into a different location in the DOM. But how?

Let's introduce the Portals from ReactDOM !

Portals provide a way to render children in a DOM node that exists outside of the DOM component hierarchy, that is, outside of the #root or #app div of your React application.

First, let's add a new div to our html and give it a 'modal-app' ID. React does not create a new div, but displays the children in that modal-app div.

Note that the #modal-app can be any valid element of the DOM (div, section, span...), regardless of its position.

React Modal HTML

And for our component to be inserted in this #modal-app div, let's use the createPortal() method offered by ReactDOM.

React Modal ReactDOM

Even though a portal can be anywhere in the DOM tree, it behaves like a normal React child in every other way. Features like context work exactly the same regardless of whether the child is a portal, as the portal still exists in the React tree regardless of position in the DOM tree.

Source : Portals - React

So let's include this method for our component like this:

React Modal Portals

Open the Modal

Logically, it will be the parent component that will ask the modal to open. But how could we proceed?

First of all, let's add a local state to our Modal component in order to know if the modal is open or not.

useState allows us to create our state with a boolean value. A defaultOpened prop will tell us if we want to open the modal directly on create. false is the default value.

Open React Modal

  • isOpen true === Modal opened
  • isOpen false === Modal closed

We use the conditionally rendering with the JavaScript conditional operator.

Conditionally rendering

Then, in order for the parent to change this local state, you'll have to call up the "refs".

This is where useRef, useImperativeHandle and forwardRef come in.

To call setIsOpen from the parent component, we need to attach a reference to our Modal.

  • useRef is used to attach a reference to our modal.
  • forwardRef is used to forward the reference to the Modal component.
  • useImperativeHandle is used to expose methods to the parent component.

React Modal Opening

Close the Modal

Then, there are several ways to leave a modal.

  • By clicking outside the content of the modal.
  • By using the small cross (x) of our content.
  • By using the ESCAP key of the keyboard.

First, let's capture the keydown event and check if the user use the ESCAP key of his keyboard.

useEffect allowing us to create a listener on the keydown event ONLY if the modal is open. If the user uses the ESCAP key on his keyboard, then the modal closes.

The result is:

React Modal close

The CSS !

You can find the css code here.

Usage

React Modal usage

Voilaaa ! Feel free to add your own modifications !

Cheers

Top comments (10)

Collapse
 
haimbuchbut profile image
Haim Buchbut • Edited

When I call modal.current.open() from the onClick() handler I'm getting that modal.current is null. Any idea what could be the reason?

const ObjList = () => {

const modal = useRef(null);

return (






Hello World



...



)

}
Collapse
 
michael_liss_65e02283cb0b profile image
Michael Liss

Super article, what I would like to know is how to launch the modal dialog after a call to a redux action ( from a button click )

In other words, the user is modifying something, they click the “save” button, the call to the API is made, and THEN the modal is shown such as “successfully saved”

Collapse
 
luiscode92 profile image
Luis Enrique Sanjuan Melo

HEy how can I send propr to the modal? lets say that I want to zoom a img from the parent to a modal(child) how can I pass the img as a prop?

Collapse
 
machy44 profile image
machy44

Nice one. I always prefer that modal's manages its own visibility state. Also in IMHO excellent example of using useImperativeHandle hook.

Collapse
 
sajadzmani profile image
sajad zamani

ok i have a question for u . if we using state every change make all components in that rerender.
and then we can forward a function. way u forward a ref instead a function.
less render? or more speed ? what ?

Collapse
 
jasurkurbanov profile image
Jasur Kurbanov

can I use your code for production and personal purposes ?

Collapse
 
viclafouch profile image
Victor de la Fouchardière

Yes :)

Collapse
 
litalg8 profile image
litalg8

Hi, So can you only open this modal from the same component where the click button to open it is? the implementation isn't really working.

Collapse
 
viclafouch profile image
Victor de la Fouchardière

Nop, just forward your ref to your component.. Or better, share it by using the Context API. There are always solutions ;)

Collapse
 
keenanpayne profile image
Keenan Payne

Thank you for sharing! I was struggling to figure out how to build reusable modal components with React and this helped 👍🏻