Skip to content
react

How to close a modal in React when clicked outside

Nov 2, 2022Abhishek EH13 Min Read
How to close a modal in React when clicked outside

In this article, we will see how to create a modal in React and close it when clicked outside.

Project setup

First, create a react app using the following command:

1npx create-react-app react-modal

Now update the index.css with the following styles. These are some styles that will be used to style and align the modal:

index.css
1body {
2 display: flex;
3 justify-content: center;
4}
5.modal {
6 position: fixed;
7 background-color: rgba(0, 0, 0, 0.5);
8 left: 0;
9 right: 0;
10 top: 0;
11 bottom: 0;
12 display: flex;
13 justify-content: center;
14 align-items: center;
15}
16
17.modal-content {
18 background-color: white;
19 width: 600px;
20 border-radius: 5px;
21}
22.modal-title {
23 padding: 0.8rem;
24 font-size: 1.5rem;
25 border-bottom: 1px solid #aaa;
26 text-align: center;
27}
28.modal-body {
29 padding: 1rem;
30}
31.modal-footer {
32 border-top: 1px solid #aaa;
33 padding: 0.8rem;
34 display: flex;
35 justify-content: flex-end;
36}
37.modal-footer button {
38 cursor: pointer;
39}

In the index.html file, which can be found inside the public directory, add a div with id modal-root:

index.html
1<!DOCTYPE html>
2<html lang="en">
3 <head>
4 <meta charset="utf-8" />
5 <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
6 <meta name="viewport" content="width=device-width, initial-scale=1" />
7 <meta name="theme-color" content="#000000" />
8 <meta
9 name="description"
10 content="Web site created using create-react-app"
11 />
12 <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
13 <!--
14 manifest.json provides metadata used when your web app is installed on a
15 user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
16 -->
17 <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
18 <!--
19 Notice the use of %PUBLIC_URL% in the tags above.
20 It will be replaced with the URL of the `public` folder during the build.
21 Only files inside the `public` folder can be referenced from the HTML.
22
23 Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
24 work correctly both with client-side routing and a non-root public URL.
25 Learn how to configure a non-root public URL by running `npm run build`.
26 -->
27 <title>React App</title>
28 </head>
29 <body>
30 <noscript>You need to enable JavaScript to run this app.</noscript>
31 <div id="root"></div>
32 <div id="modal-root"></div>
33 <!--
34 This HTML file is a template.
35 If you open it directly in the browser, you will see an empty page.
36
37 You can add webfonts, meta tags, or analytics to this file.
38 The build step will place the bundled scripts into the <body> tag.
39
40 To begin the development, run `npm start` or `yarn start`.
41 To create a production bundle, use `npm run build` or `yarn build`.
42 -->
43 </body>
44</html>

Now create a component called Modal.js with the following code:

Modal.js
1import React, { useEffect } from "react"
2import ReactDOM from "react-dom"
3
4const Modal = ({ onClose }) => {
5 useEffect(() => {
6 document.body.style.overflow = "hidden"
7 return () => {
8 document.body.style.overflow = "auto"
9 }
10 }, [])
11 return ReactDOM.createPortal(
12 <div className="modal">
13 <div className="modal-content">
14 <div className="modal-title">Modal Title</div>
15 <div className="modal-body">
16 Lorem, ipsum dolor sit amet consectetur adipisicing elit. Quaerat,
17 sint ab ex odio pariatur et eius? Nam, quod eum adipisci earum nisi
18 tempora, nesciunt esse voluptate illo, maxime consectetur harum!
19 </div>
20 <div className="modal-footer">
21 <button onClick={onClose}>Close</button>
22 </div>
23 </div>
24 </div>,
25 document.getElementById("modal-root")
26 )
27}
28
29export default Modal

Here we are creating a react portal and mounting it to the div with the id modal-root, created earlier. We need to create the modal in a separate div outside the root div so that we can render the modal on top of the existing content.

Here we have a useEffect hook, which is used to hide the scrollbar when the modal is open so that the scrolling is blocked when the modal is open.

Now in App.js, create enough content to induce a scrollbar and add a button, when clicked will open the modal.

App.js
1import { useState } from "react"
2import Modal from "./Modal"
3
4function App() {
5 const [isModalOpen, setIsModalOpen] = useState(false)
6 return (
7 <div>
8 <p>
9 Lorem, ipsum dolor sit amet consectetur adipisicing elit. Distinctio
10 vero facere necessitatibus ipsum, veritatis autem natus eius, fugiat hic
11 eligendi dignissimos voluptatum. Recusandae corrupti dolorem consectetur
12 sequi excepturi inventore facilis! Consequatur non ullam magni fugiat
13 natus expedita saepe voluptatem impedit est odio! Sint consequatur aut
14 maiores illum. Libero eos sapiente adipisci aliquid nisi magnam ad qui
15 minus voluptate, id et? Unde eum ea excepturi expedita ipsa debitis
16 corrupti? Ex voluptatem assumenda velit consectetur! Rerum, rem
17 laudantium accusantium vitae vero ipsa delectus corporis quibusdam
18 nihil, explicabo aliquam necessitatibus dignissimos sint labore. Optio
19 itaque quo earum iusto, ipsum eius culpa consequatur, nihil, tempore
20 inventore a dolor eos deserunt vitae sit aliquam? Molestiae quia
21 inventore omnis pariatur consectetur sit sed, labore mollitia quis!
22 Voluptatem consequatur sit corporis itaque, repudiandae temporibus id
23 sint similique qui? Odio minus nam quia dignissimos fuga consectetur
24 commodi minima adipisci nulla eius optio sunt explicabo quidem, vero
25 tenetur voluptatibus? Ex possimus iste necessitatibus vero commodi natus
26 iure tempore dicta neque laudantium, libero ullam odit quibusdam nobis
27 voluptate molestiae. Mollitia facere iusto maiores eius quisquam ab
28 architecto voluptatum veniam exercitationem. Suscipit magnam veritatis
29 enim? Qui excepturi nemo aperiam numquam libero assumenda recusandae
30 quos dignissimos possimus mollitia non deleniti aut expedita soluta
31 nobis eaque, tempora laboriosam animi consectetur nam sit veniam?
32 Voluptatem temporibus, saepe quos eum enim ipsum accusamus qui? Odio
33 quidem magni reprehenderit dolores saepe nemo tenetur eaque labore
34 assumenda. Explicabo placeat non mollitia a quos, dolor laborum suscipit
35 quaerat! Recusandae, nemo adipisci nihil ipsum vero quia accusantium
36 non? Eligendi in ex quo sint repellat ab, nemo delectus. Consequuntur
37 non officia eos temporibus quis odit dolor ratione praesentium quae ex.
38 Iste vel necessitatibus, facilis, minima nihil ullam obcaecati non ipsam
39 tenetur dicta fugit explicabo accusantium rerum autem? Dolores vero quia
40 nam animi quis, non deserunt officiis quasi natus ipsa accusamus.
41 Dolores optio saepe dignissimos fugiat autem aliquid perspiciatis,
42 consequuntur provident? Dignissimos eligendi facilis vero eaque,
43 consequatur tempore, labore aperiam, cupiditate dolores praesentium
44 amet? Eius nemo quisquam animi enim blanditiis doloremque? Inventore
45 quisquam officiis itaque animi culpa suscipit, iusto obcaecati sapiente,
46 facere architecto tenetur, laudantium repellendus quis nisi! Voluptatem
47 adipisci fugit facere libero consequuntur magni consequatur, totam
48 magnam necessitatibus minima illum? Possimus a commodi labore architecto
49 autem dicta officiis harum vitae quos repellendus, nesciunt
50 exercitationem amet, expedita libero explicabo, dolores sapiente
51 laudantium modi? Excepturi explicabo debitis neque optio corporis non
52 atque. Dolorem aliquid sed, quasi officia dolores temporibus rem nulla
53 eligendi fugit consectetur praesentium, iusto quam! Ipsam voluptatum
54 assumenda facere, saepe, iste maiores placeat, earum quos neque at
55 deleniti omnis eos. Ipsam sequi provident quis qui mollitia doloribus
56 magnam recusandae et ratione earum dolore fugit itaque, laborum eligendi
57 similique inventore. Incidunt quo officia et ea minus soluta voluptas
58 est illum minima! Libero, voluptate. Illum praesentium in suscipit
59 numquam necessitatibus beatae quaerat officia architecto.
60 </p>
61 <button onClick={() => setIsModalOpen(true)}>Open Modal</button>
62 {isModalOpen && <Modal onClose={() => setIsModalOpen(false)} />}
63 <p>
64 Lorem ipsum dolor, sit amet consectetur adipisicing elit. Illum iure id
65 repudiandae, aspernatur ea ut corporis provident explicabo minus odit
66 commodi, labore optio unde delectus tenetur vitae necessitatibus. Ullam,
67 illo. Maxime doloremque rerum eius quae aspernatur accusantium tempore
68 nobis, sapiente officia, non necessitatibus aperiam omnis assumenda
69 quisquam cum esse eligendi nemo laudantium nihil labore aliquid modi
70 vel! Quos, quo tempora! Dolore libero quos alias ipsum unde dolor nisi
71 sed perferendis laborum non sunt corporis a quam aliquam, eveniet
72 doloribus laboriosam sequi cupiditate deleniti, molestiae recusandae, ut
73 labore minima! Vero, eos. Reiciendis nostrum itaque placeat perferendis
74 doloremque earum cupiditate nihil voluptatibus officia excepturi odio
75 ipsam molestias similique quibusdam, doloribus minus culpa. Provident
76 similique dolor assumenda magnam eveniet, vitae aspernatur recusandae
77 nesciunt. Culpa sint minus sunt iste distinctio ipsa perferendis debitis
78 nostrum provident? Neque totam doloribus obcaecati, accusantium aliquid
79 suscipit nobis alias illo nostrum eius harum quasi explicabo voluptatem
80 architecto molestiae veritatis. Quis quibusdam eius perferendis odio
81 illum et unde! Repellat facilis autem earum quidem voluptatem. Itaque
82 cumque ipsum nostrum libero corrupti sequi temporibus voluptas commodi
83 quia, molestiae a unde eveniet aperiam. Commodi veniam aspernatur nam
84 quas blanditiis tempore harum hic? Perspiciatis, excepturi! Ratione ex
85 vero reiciendis cum eos est vitae eius dignissimos quo necessitatibus
86 aut fugit amet dicta, deserunt ad libero. Animi incidunt dolorem magnam
87 natus qui rem inventore impedit, accusamus ratione, consequatur
88 repellendus harum error autem nemo quos repudiandae itaque, amet beatae.
89 Aut, fugit ea necessitatibus odio veniam illo sit? Explicabo quasi fuga
90 non sed magni corporis tenetur delectus dolore! Praesentium rerum facere
91 illo delectus harum commodi porro repudiandae quas! Sint eligendi
92 dolore, minima nostrum facilis dolorum quisquam dolores amet? Vitae
93 incidunt, corrupti dolorum, voluptatem mollitia aspernatur perspiciatis
94 dicta repudiandae ut eligendi id et vero. Consectetur illum ipsum unde!
95 Iste porro ab nobis officiis, vero debitis consectetur ipsa error
96 reprehenderit? Nulla eaque unde saepe inventore quas? Mollitia
97 aspernatur eum expedita! Ipsa quia maxime repellendus non nisi.
98 Accusamus, doloremque. Obcaecati quisquam voluptates natus reprehenderit
99 ratione cupiditate iusto tenetur soluta doloremque. Facilis. Quo id
100 illum voluptatibus quod ducimus error similique ut facere, quas iusto
101 eius eveniet consectetur deserunt magnam natus ex. Culpa beatae
102 voluptatem sit inventore odit voluptate reprehenderit fuga, qui
103 mollitia! Doloribus rerum ipsam atque, laudantium impedit consequatur
104 doloremque corrupti optio laboriosam incidunt unde sint, aliquam velit
105 dolor quod autem, quisquam maxime est provident porro culpa? Corporis
106 voluptas aut suscipit nesciunt. Sed itaque nihil, sit eaque amet odit
107 libero necessitatibus illo blanditiis ut tempora explicabo. Eius odio
108 ducimus hic voluptates, voluptatibus culpa velit consequuntur tempora
109 quaerat aliquid quas. Explicabo, soluta voluptatibus. Quod dolorem eaque
110 consequatur neque ipsa laborum fuga minus? Atque culpa cupiditate,
111 aperiam quod soluta voluptatum sint sit iure minus asperiores rerum.
112 Minima officia animi, molestiae dolorem autem reprehenderit a? Porro
113 excepturi, corporis nihil et rerum recusandae minus impedit quaerat
114 sapiente ducimus earum ipsa aspernatur vero magnam maiores quae facilis
115 laudantium? Illum ipsam aperiam sunt voluptatum. Delectus explicabo
116 laborum maxime! Reprehenderit maxime dignissimos cumque tenetur
117 necessitatibus maiores molestiae quisquam ipsum explicabo. Consequuntur
118 ad sapiente reprehenderit, ipsum et exercitationem quod dolore!
119 Consectetur nihil earum aliquam aspernatur, excepturi consequuntur
120 tempore libero autem. Vitae enim nihil ut? Veniam consequatur explicabo
121 fuga commodi assumenda? Laborum cum non voluptatibus error accusantium
122 fugit, deleniti iusto et. Quidem culpa minima fuga unde, deserunt facere
123 modi dolorem voluptatibus? Delectus, fugit ducimus magnam non ut quos
124 aspernatur iste impedit qui, dignissimos excepturi eos corrupti
125 voluptatum, repellendus ipsam deleniti suscipit harum repellat
126 voluptates dolorem. Alias id fuga laboriosam eligendi quibusdam? Libero
127 ullam pariatur incidunt optio a voluptas, iusto laboriosam cumque quas
128 architecto numquam tempora inventore maiores dignissimos explicabo
129 suscipit distinctio vero provident. Fugit nobis reiciendis
130 exercitationem soluta dicta dolorum consequuntur. Consequatur itaque
131 maxime quaerat. Aut rem praesentium deleniti dolor odio nisi, dolores at
132 eveniet cupiditate expedita maiores optio veritatis esse impedit beatae
133 commodi nostrum quam delectus explicabo laboriosam asperiores molestiae!
134 Omnis culpa iste illo perferendis vitae reprehenderit facere, voluptate
135 aspernatur accusantium ad sit, animi velit ex dolor eos, laborum
136 molestias? A porro maiores, nostrum laborum non mollitia unde aspernatur
137 quo. Voluptatibus maxime quis blanditiis vitae cupiditate quo vel
138 voluptates consectetur sequi commodi dolorem, rerum, maiores officiis
139 nobis expedita! Ducimus nostrum vitae omnis ad rerum atque animi ipsum!
140 Quisquam, doloribus autem! Aut sapiente explicabo maiores dolores
141 commodi tempore eligendi quibusdam distinctio ducimus, consequuntur in
142 enim nobis rerum mollitia aspernatur odio deserunt officia veniam beatae
143 officiis. Quibusdam tempore numquam dolore officia ad? Consequatur
144 repellat hic atque commodi amet error unde voluptates mollitia illum
145 placeat eaque maiores dolorem corrupti, quae provident magnam incidunt
146 earum. Libero praesentium ipsa voluptates, in architecto corporis
147 aliquid nostrum. Veniam aperiam perspiciatis aliquam placeat, excepturi
148 recusandae vel ex! Mollitia fugit blanditiis vel! Quaerat voluptas illum
149 non laboriosam quia voluptatem amet tenetur debitis nobis totam! Sint
150 perferendis velit maiores fugiat. Voluptatum at praesentium doloremque
151 amet illum magni provident tenetur earum qui harum ex voluptatibus
152 aliquid, nemo culpa. Totam corrupti, quas, quos nesciunt facere eius
153 delectus optio recusandae voluptatibus debitis quasi. Quasi,
154 voluptatibus consectetur ipsum accusantium molestiae est voluptatum
155 aperiam? Delectus architecto, culpa et labore repudiandae minus
156 quibusdam autem inventore adipisci eligendi laborum obcaecati quasi
157 maxime! Molestiae minima laborum maiores laudantium. Facere inventore
158 eligendi quibusdam corporis nulla ab dolore, ipsam et ea consectetur est
159 aliquam rem deserunt culpa deleniti cumque unde exercitationem
160 laudantium labore? Nulla, tenetur ducimus delectus quia totam amet. Quia
161 neque sed ad incidunt, voluptas veniam voluptatum mollitia soluta
162 doloribus temporibus qui debitis eveniet sequi aut ullam impedit
163 voluptates molestias ipsa alias vitae illum. Ex nostrum obcaecati sequi
164 odio. Consequuntur laborum odit ut voluptatibus adipisci officiis,
165 aperiam recusandae enim atque commodi dignissimos error magni sunt
166 libero illo! Iusto rerum pariatur nisi quaerat, repellendus soluta vitae
167 velit labore expedita officiis! Ratione totam nemo accusamus. Nemo autem
168 nesciunt, sequi quia eaque, est, odio esse praesentium debitis aperiam
169 voluptatem omnis deleniti. Omnis sequi sunt quasi modi dolore rem quam
170 accusamus similique voluptas. Reprehenderit eaque esse sint inventore
171 facere numquam soluta nemo unde, necessitatibus rerum vel quos deleniti
172 similique, atque perspiciatis recusandae. Numquam, illum nemo unde
173 necessitatibus fuga perspiciatis reprehenderit a sunt iste! Perferendis
174 pariatur numquam neque iure tenetur nisi maxime exercitationem inventore
175 tempore harum quaerat officiis magni fugit laboriosam placeat in, est
176 hic repudiandae molestias odio. Voluptatibus laboriosam alias temporibus
177 eveniet laudantium! Nesciunt doloremque exercitationem quae quas
178 consequatur ex suscipit odio, doloribus delectus? Consectetur culpa
179 earum non, inventore, iste architecto libero facere eligendi a,
180 explicabo sed nostrum? Rem fuga voluptas ea voluptatem. Sint, voluptate
181 voluptatibus! Similique voluptate et quibusdam veniam perspiciatis
182 deserunt impedit earum, optio consequatur voluptatum est reprehenderit
183 in beatae sapiente hic pariatur rem distinctio. Iure expedita ipsum
184 impedit minus harum. Dolore illum repellendus cupiditate quo dolor sint,
185 deserunt nesciunt magni corporis inventore eos quaerat vitae quas esse
186 minus dolorum illo suscipit soluta repudiandae, blanditiis ipsam
187 commodi, consequatur eaque doloremque.
188 </p>
189 </div>
190 )
191}
192
193export default App

In the above code, we are maintaining a local state to store if the modal is open. If the state is true, we are displaying the modal. We are passing a callback named onClose, which will set the state to false so that the modal can be closed.

Now, if you run the app and click on the button, you should be able to see the modal.

Closing the modal when clicked outside

As of now, if you click outside the modal, nothing will happen. To close the modal when the user clicks outside, first, we need to detect if the user has clicked outside.

For that we can make use of refs:

Modal.js
1import React, { useEffect, useRef } from "react"
2import ReactDOM from "react-dom"
3
4const Modal = ({ onClose }) => {
5 const ref = useRef()
6 useEffect(() => {
7 const checkIfClickedOutside = e => {
8 if (ref.current && !ref.current.contains(e.target)) {
9 onClose()
10 }
11 }
12 document.addEventListener("click", checkIfClickedOutside)
13 return () => {
14 document.removeEventListener("click", checkIfClickedOutside)
15 }
16 }, [onClose])
17
18 useEffect(() => {
19 document.body.style.overflow = "hidden"
20 return () => {
21 document.body.style.overflow = "auto"
22 }
23 }, [])
24 return ReactDOM.createPortal(
25 <div className="modal">
26 <div className="modal-content" ref={ref}>
27 <div className="modal-title">Modal Title</div>
28 <div className="modal-body">
29 Lorem, ipsum dolor sit amet consectetur adipisicing elit. Quaerat,
30 sint ab ex odio pariatur et eius? Nam, quod eum adipisci earum nisi
31 tempora, nesciunt esse voluptate illo, maxime consectetur harum!
32 </div>
33 <div className="modal-footer">
34 <button onClick={onClose}>Close</button>
35 </div>
36 </div>
37 </div>,
38 document.getElementById("modal-root")
39 )
40}
41
42export default Modal

Here we have created a reference to the modal-content div and in the useEffect we check if the div contains (is inside) the clicked target. If that is not the case (not condition), then we close the modal.

Source code and Demo

You can view the complete source code here and a demo here.

Do follow me on twitter where I post developer insights more often!

© 2024 CodingDeft.Com