Table of Contents
If you are looking for closing a modal when clicked outside, you can refer this article.
You might have come across instances where you would want to do certain actions when the user clicks outside a component, say like closing a modal or a dropdown menu. In this tutorial, we will display a dropdown and close the dropdown when the user clicks outside it.
Setting up the Project
Create a react project using the following command:
1npx create-react-app react-on-click-outside
Adding styles
Update the index.css
with the following styles. Here we are adding some basic styling for our button and the dropdown list.
1body {2 margin: 0 auto;3 max-width: 500px;4}5.wrapper {6 display: inline-flex;7 flex-direction: column;8}910.button {11 margin: 20px 0px 0px 0px;12 border: 1px solid #2185d0;13 padding: 10px;14 border-radius: 5px;15 cursor: pointer;16 font-weight: bold;17 background-color: white;18 width: 140px;19}2021.list {22 box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);23 border: 1px solid #ccc;24 list-style-type: none;25 padding: 0;26 margin: 0;27 width: auto;28 display: inline-block;29}30.list-item {31 padding: 8px;32 cursor: pointer;33 background-color: white;34}35.list-item:hover,36.list-item:active {37 background-color: #f3f3f3;38}
Creating the dropdown list
In the App.js
, let's create a button and a dropdown list, which will be displayed when the button is clicked.
1import { useState } from "react"23function App() {4 const [isMenuOpen, setIsMenuOpen] = useState(false)56 return (7 <div className="wrapper">8 <button9 className="button"10 onClick={() => setIsMenuOpen(oldState => !oldState)}11 >12 Click Me13 </button>14 {isMenuOpen && (15 <ul className="list">16 <li className="list-item">dropdown option 1</li>17 <li className="list-item">dropdown option 2</li>18 <li className="list-item">dropdown option 3</li>19 <li className="list-item">dropdown option 4</li>20 </ul>21 )}22 </div>23 )24}2526export default App
Now if you run the app and click on the button, you will be able to see the dropdown as shown below:
Closing the dropdown when clicked outside
Using the contains API,
we can identify whether a target node (the component on which the user has clicked) is inside a particular node or not.
That is, if the clicked component is within (or itself) the component we are interested in, then it will return true
otherwise false
.
In our case the interested component is the list and the dropdown. So we will add a ref
to that component which wraps both of them.
1import { useEffect, useRef, useState } from "react"23function App() {4 const ref = useRef()56 const [isMenuOpen, setIsMenuOpen] = useState(false)78 useEffect(() => {9 const checkIfClickedOutside = e => {10 // If the menu is open and the clicked target is not within the menu,11 // then close the menu12 if (isMenuOpen && ref.current && !ref.current.contains(e.target)) {13 setIsMenuOpen(false)14 }15 }1617 document.addEventListener("mousedown", checkIfClickedOutside)1819 return () => {20 // Cleanup the event listener21 document.removeEventListener("mousedown", checkIfClickedOutside)22 }23 }, [isMenuOpen])2425 return (26 <div className="wrapper" ref={ref}>27 <button28 className="button"29 onClick={() => setIsMenuOpen(oldState => !oldState)}30 >31 Click Me32 </button>33 {isMenuOpen && (34 <ul className="list">35 <li className="list-item">dropdown option 1</li>36 <li className="list-item">dropdown option 2</li>37 <li className="list-item">dropdown option 3</li>38 <li className="list-item">dropdown option 4</li>39 </ul>40 )}41 </div>42 )43}4445export default App
Also, we are running an effect whenever the state of the menu changes and we are binding a mousedown
event to the document
so that whenever the user clicks on the document, we can check if it is inside or outside the wrapper and hide the list accordingly.
Now if you run the app and click on the button and click outside the list, the list will be closed.
Demo and source code
You can view a demo here and the complete source code here.
Do follow me on twitter where I post developer insights more often!
Comments