How to detect click outside in a React component
Tags: react, hooks
Published: 2021-06-04 05:16:42

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.

{% youtube Hl7o4tJQzPs %}

# Setting up the Project

Create a react project using the following command:

```bash
npx 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.

```css
body {
  margin: 0 auto;
  max-width: 500px;
}
.wrapper {
  display: inline-flex;
  flex-direction: column;
}

.button {
  margin: 20px 0px 0px 0px;
  border: 1px solid #2185d0;
  padding: 10px;
  border-radius: 5px;
  cursor: pointer;
  font-weight: bold;
  background-color: white;
  width: 140px;
}

.list {
  box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
  border: 1px solid #ccc;
  list-style-type: none;
  padding: 0;
  margin: 0;
  width: auto;
  display: inline-block;
}
.list-item {
  padding: 8px;
  cursor: pointer;
  background-color: white;
}
.list-item:hover,
.list-item:active {
  background-color: #f3f3f3;
}
```

# 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.

```js
import { useState } from "react"

function App() {
  const [isMenuOpen, setIsMenuOpen] = useState(false)

  return (
    <div className="wrapper">
      <button className="button" onClick={() => setIsMenuOpen(true)}>
        Click Me
      </button>
      {isMenuOpen && (
        <ul className="list">
          <li className="list-item">dropdown option 1</li>
          <li className="list-item">dropdown option 2</li>
          <li className="list-item">dropdown option 3</li>
          <li className="list-item">dropdown option 4</li>
        </ul>
      )}
    </div>
  )
}

export default App
```

Now if you run the app and click on the button, you will be able to see the dropdown as shown below:

![dropdown](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/08d6cqnepphuhk4kf4yr.png)

# Closing the dropdown when clicked outside

Using the [contains API](https://developer.mozilla.org/en-US/docs/Web/API/Node/contains), 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. So we will add a `ref` to that component

```jsx
import { useEffect, useRef, useState } from "react"

function App() {
  const ref = useRef()

  const [isMenuOpen, setIsMenuOpen] = useState(false)

  useEffect(() => {
    const checkIfClickedOutside = e => {
      // If the menu is open and the clicked target is not within the menu,
      // then close the menu
      if (isMenuOpen && ref.current && !ref.current.contains(e.target)) {
        setIsMenuOpen(false)
      }
    }

    document.addEventListener("mousedown", checkIfClickedOutside)

    return () => {
      // Cleanup the event listener
      document.removeEventListener("mousedown", checkIfClickedOutside)
    }
  }, [isMenuOpen])

  return (
    <div className="wrapper">
      <button className="button" onClick={() => setIsMenuOpen(true)}>
        Click Me
      </button>
      {isMenuOpen && (
        <ul className="list" ref={ref}>
          <li className="list-item">dropdown option 1</li>
          <li className="list-item">dropdown option 2</li>
          <li className="list-item">dropdown option 3</li>
          <li className="list-item">dropdown option 4</li>
        </ul>
      )}
    </div>
  )
}

export 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 list 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](https://react-on-click-outside.vercel.app/) and the complete source code [here](https://github.com/collegewap/react-on-click-outside).