Table of Contents
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:
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}1617.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
:
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 <meta9 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 a15 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.2223 Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will24 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.3637 You can add webfonts, meta tags, or analytics to this file.38 The build step will place the bundled scripts into the <body> tag.3940 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:
1import React, { useEffect } from "react"2import ReactDOM from "react-dom"34const 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 nisi18 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}2829export 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.
1import { useState } from "react"2import Modal from "./Modal"34function App() {5 const [isModalOpen, setIsModalOpen] = useState(false)6 return (7 <div>8 <p>9 Lorem, ipsum dolor sit amet consectetur adipisicing elit. Distinctio10 vero facere necessitatibus ipsum, veritatis autem natus eius, fugiat hic11 eligendi dignissimos voluptatum. Recusandae corrupti dolorem consectetur12 sequi excepturi inventore facilis! Consequatur non ullam magni fugiat13 natus expedita saepe voluptatem impedit est odio! Sint consequatur aut14 maiores illum. Libero eos sapiente adipisci aliquid nisi magnam ad qui15 minus voluptate, id et? Unde eum ea excepturi expedita ipsa debitis16 corrupti? Ex voluptatem assumenda velit consectetur! Rerum, rem17 laudantium accusantium vitae vero ipsa delectus corporis quibusdam18 nihil, explicabo aliquam necessitatibus dignissimos sint labore. Optio19 itaque quo earum iusto, ipsum eius culpa consequatur, nihil, tempore20 inventore a dolor eos deserunt vitae sit aliquam? Molestiae quia21 inventore omnis pariatur consectetur sit sed, labore mollitia quis!22 Voluptatem consequatur sit corporis itaque, repudiandae temporibus id23 sint similique qui? Odio minus nam quia dignissimos fuga consectetur24 commodi minima adipisci nulla eius optio sunt explicabo quidem, vero25 tenetur voluptatibus? Ex possimus iste necessitatibus vero commodi natus26 iure tempore dicta neque laudantium, libero ullam odit quibusdam nobis27 voluptate molestiae. Mollitia facere iusto maiores eius quisquam ab28 architecto voluptatum veniam exercitationem. Suscipit magnam veritatis29 enim? Qui excepturi nemo aperiam numquam libero assumenda recusandae30 quos dignissimos possimus mollitia non deleniti aut expedita soluta31 nobis eaque, tempora laboriosam animi consectetur nam sit veniam?32 Voluptatem temporibus, saepe quos eum enim ipsum accusamus qui? Odio33 quidem magni reprehenderit dolores saepe nemo tenetur eaque labore34 assumenda. Explicabo placeat non mollitia a quos, dolor laborum suscipit35 quaerat! Recusandae, nemo adipisci nihil ipsum vero quia accusantium36 non? Eligendi in ex quo sint repellat ab, nemo delectus. Consequuntur37 non officia eos temporibus quis odit dolor ratione praesentium quae ex.38 Iste vel necessitatibus, facilis, minima nihil ullam obcaecati non ipsam39 tenetur dicta fugit explicabo accusantium rerum autem? Dolores vero quia40 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 praesentium44 amet? Eius nemo quisquam animi enim blanditiis doloremque? Inventore45 quisquam officiis itaque animi culpa suscipit, iusto obcaecati sapiente,46 facere architecto tenetur, laudantium repellendus quis nisi! Voluptatem47 adipisci fugit facere libero consequuntur magni consequatur, totam48 magnam necessitatibus minima illum? Possimus a commodi labore architecto49 autem dicta officiis harum vitae quos repellendus, nesciunt50 exercitationem amet, expedita libero explicabo, dolores sapiente51 laudantium modi? Excepturi explicabo debitis neque optio corporis non52 atque. Dolorem aliquid sed, quasi officia dolores temporibus rem nulla53 eligendi fugit consectetur praesentium, iusto quam! Ipsam voluptatum54 assumenda facere, saepe, iste maiores placeat, earum quos neque at55 deleniti omnis eos. Ipsam sequi provident quis qui mollitia doloribus56 magnam recusandae et ratione earum dolore fugit itaque, laborum eligendi57 similique inventore. Incidunt quo officia et ea minus soluta voluptas58 est illum minima! Libero, voluptate. Illum praesentium in suscipit59 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 id65 repudiandae, aspernatur ea ut corporis provident explicabo minus odit66 commodi, labore optio unde delectus tenetur vitae necessitatibus. Ullam,67 illo. Maxime doloremque rerum eius quae aspernatur accusantium tempore68 nobis, sapiente officia, non necessitatibus aperiam omnis assumenda69 quisquam cum esse eligendi nemo laudantium nihil labore aliquid modi70 vel! Quos, quo tempora! Dolore libero quos alias ipsum unde dolor nisi71 sed perferendis laborum non sunt corporis a quam aliquam, eveniet72 doloribus laboriosam sequi cupiditate deleniti, molestiae recusandae, ut73 labore minima! Vero, eos. Reiciendis nostrum itaque placeat perferendis74 doloremque earum cupiditate nihil voluptatibus officia excepturi odio75 ipsam molestias similique quibusdam, doloribus minus culpa. Provident76 similique dolor assumenda magnam eveniet, vitae aspernatur recusandae77 nesciunt. Culpa sint minus sunt iste distinctio ipsa perferendis debitis78 nostrum provident? Neque totam doloribus obcaecati, accusantium aliquid79 suscipit nobis alias illo nostrum eius harum quasi explicabo voluptatem80 architecto molestiae veritatis. Quis quibusdam eius perferendis odio81 illum et unde! Repellat facilis autem earum quidem voluptatem. Itaque82 cumque ipsum nostrum libero corrupti sequi temporibus voluptas commodi83 quia, molestiae a unde eveniet aperiam. Commodi veniam aspernatur nam84 quas blanditiis tempore harum hic? Perspiciatis, excepturi! Ratione ex85 vero reiciendis cum eos est vitae eius dignissimos quo necessitatibus86 aut fugit amet dicta, deserunt ad libero. Animi incidunt dolorem magnam87 natus qui rem inventore impedit, accusamus ratione, consequatur88 repellendus harum error autem nemo quos repudiandae itaque, amet beatae.89 Aut, fugit ea necessitatibus odio veniam illo sit? Explicabo quasi fuga90 non sed magni corporis tenetur delectus dolore! Praesentium rerum facere91 illo delectus harum commodi porro repudiandae quas! Sint eligendi92 dolore, minima nostrum facilis dolorum quisquam dolores amet? Vitae93 incidunt, corrupti dolorum, voluptatem mollitia aspernatur perspiciatis94 dicta repudiandae ut eligendi id et vero. Consectetur illum ipsum unde!95 Iste porro ab nobis officiis, vero debitis consectetur ipsa error96 reprehenderit? Nulla eaque unde saepe inventore quas? Mollitia97 aspernatur eum expedita! Ipsa quia maxime repellendus non nisi.98 Accusamus, doloremque. Obcaecati quisquam voluptates natus reprehenderit99 ratione cupiditate iusto tenetur soluta doloremque. Facilis. Quo id100 illum voluptatibus quod ducimus error similique ut facere, quas iusto101 eius eveniet consectetur deserunt magnam natus ex. Culpa beatae102 voluptatem sit inventore odit voluptate reprehenderit fuga, qui103 mollitia! Doloribus rerum ipsam atque, laudantium impedit consequatur104 doloremque corrupti optio laboriosam incidunt unde sint, aliquam velit105 dolor quod autem, quisquam maxime est provident porro culpa? Corporis106 voluptas aut suscipit nesciunt. Sed itaque nihil, sit eaque amet odit107 libero necessitatibus illo blanditiis ut tempora explicabo. Eius odio108 ducimus hic voluptates, voluptatibus culpa velit consequuntur tempora109 quaerat aliquid quas. Explicabo, soluta voluptatibus. Quod dolorem eaque110 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? Porro113 excepturi, corporis nihil et rerum recusandae minus impedit quaerat114 sapiente ducimus earum ipsa aspernatur vero magnam maiores quae facilis115 laudantium? Illum ipsam aperiam sunt voluptatum. Delectus explicabo116 laborum maxime! Reprehenderit maxime dignissimos cumque tenetur117 necessitatibus maiores molestiae quisquam ipsum explicabo. Consequuntur118 ad sapiente reprehenderit, ipsum et exercitationem quod dolore!119 Consectetur nihil earum aliquam aspernatur, excepturi consequuntur120 tempore libero autem. Vitae enim nihil ut? Veniam consequatur explicabo121 fuga commodi assumenda? Laborum cum non voluptatibus error accusantium122 fugit, deleniti iusto et. Quidem culpa minima fuga unde, deserunt facere123 modi dolorem voluptatibus? Delectus, fugit ducimus magnam non ut quos124 aspernatur iste impedit qui, dignissimos excepturi eos corrupti125 voluptatum, repellendus ipsam deleniti suscipit harum repellat126 voluptates dolorem. Alias id fuga laboriosam eligendi quibusdam? Libero127 ullam pariatur incidunt optio a voluptas, iusto laboriosam cumque quas128 architecto numquam tempora inventore maiores dignissimos explicabo129 suscipit distinctio vero provident. Fugit nobis reiciendis130 exercitationem soluta dicta dolorum consequuntur. Consequatur itaque131 maxime quaerat. Aut rem praesentium deleniti dolor odio nisi, dolores at132 eveniet cupiditate expedita maiores optio veritatis esse impedit beatae133 commodi nostrum quam delectus explicabo laboriosam asperiores molestiae!134 Omnis culpa iste illo perferendis vitae reprehenderit facere, voluptate135 aspernatur accusantium ad sit, animi velit ex dolor eos, laborum136 molestias? A porro maiores, nostrum laborum non mollitia unde aspernatur137 quo. Voluptatibus maxime quis blanditiis vitae cupiditate quo vel138 voluptates consectetur sequi commodi dolorem, rerum, maiores officiis139 nobis expedita! Ducimus nostrum vitae omnis ad rerum atque animi ipsum!140 Quisquam, doloribus autem! Aut sapiente explicabo maiores dolores141 commodi tempore eligendi quibusdam distinctio ducimus, consequuntur in142 enim nobis rerum mollitia aspernatur odio deserunt officia veniam beatae143 officiis. Quibusdam tempore numquam dolore officia ad? Consequatur144 repellat hic atque commodi amet error unde voluptates mollitia illum145 placeat eaque maiores dolorem corrupti, quae provident magnam incidunt146 earum. Libero praesentium ipsa voluptates, in architecto corporis147 aliquid nostrum. Veniam aperiam perspiciatis aliquam placeat, excepturi148 recusandae vel ex! Mollitia fugit blanditiis vel! Quaerat voluptas illum149 non laboriosam quia voluptatem amet tenetur debitis nobis totam! Sint150 perferendis velit maiores fugiat. Voluptatum at praesentium doloremque151 amet illum magni provident tenetur earum qui harum ex voluptatibus152 aliquid, nemo culpa. Totam corrupti, quas, quos nesciunt facere eius153 delectus optio recusandae voluptatibus debitis quasi. Quasi,154 voluptatibus consectetur ipsum accusantium molestiae est voluptatum155 aperiam? Delectus architecto, culpa et labore repudiandae minus156 quibusdam autem inventore adipisci eligendi laborum obcaecati quasi157 maxime! Molestiae minima laborum maiores laudantium. Facere inventore158 eligendi quibusdam corporis nulla ab dolore, ipsam et ea consectetur est159 aliquam rem deserunt culpa deleniti cumque unde exercitationem160 laudantium labore? Nulla, tenetur ducimus delectus quia totam amet. Quia161 neque sed ad incidunt, voluptas veniam voluptatum mollitia soluta162 doloribus temporibus qui debitis eveniet sequi aut ullam impedit163 voluptates molestias ipsa alias vitae illum. Ex nostrum obcaecati sequi164 odio. Consequuntur laborum odit ut voluptatibus adipisci officiis,165 aperiam recusandae enim atque commodi dignissimos error magni sunt166 libero illo! Iusto rerum pariatur nisi quaerat, repellendus soluta vitae167 velit labore expedita officiis! Ratione totam nemo accusamus. Nemo autem168 nesciunt, sequi quia eaque, est, odio esse praesentium debitis aperiam169 voluptatem omnis deleniti. Omnis sequi sunt quasi modi dolore rem quam170 accusamus similique voluptas. Reprehenderit eaque esse sint inventore171 facere numquam soluta nemo unde, necessitatibus rerum vel quos deleniti172 similique, atque perspiciatis recusandae. Numquam, illum nemo unde173 necessitatibus fuga perspiciatis reprehenderit a sunt iste! Perferendis174 pariatur numquam neque iure tenetur nisi maxime exercitationem inventore175 tempore harum quaerat officiis magni fugit laboriosam placeat in, est176 hic repudiandae molestias odio. Voluptatibus laboriosam alias temporibus177 eveniet laudantium! Nesciunt doloremque exercitationem quae quas178 consequatur ex suscipit odio, doloribus delectus? Consectetur culpa179 earum non, inventore, iste architecto libero facere eligendi a,180 explicabo sed nostrum? Rem fuga voluptas ea voluptatem. Sint, voluptate181 voluptatibus! Similique voluptate et quibusdam veniam perspiciatis182 deserunt impedit earum, optio consequatur voluptatum est reprehenderit183 in beatae sapiente hic pariatur rem distinctio. Iure expedita ipsum184 impedit minus harum. Dolore illum repellendus cupiditate quo dolor sint,185 deserunt nesciunt magni corporis inventore eos quaerat vitae quas esse186 minus dolorum illo suscipit soluta repudiandae, blanditiis ipsam187 commodi, consequatur eaque doloremque.188 </p>189 </div>190 )191}192193export 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:
1import React, { useEffect, useRef } from "react"2import ReactDOM from "react-dom"34const 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])1718 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 nisi31 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}4142export 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!