DEV Community

Cover image for How to detect click outside in a React component
collegewap
collegewap

Posted on • Edited on • Originally published at codingdeft.com

11

How to detect click outside in a React component

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:

npx create-react-app react-on-click-outside
Enter fullscreen mode Exit fullscreen mode

Adding styles

Update the index.css with the following styles. Here we are adding some basic styling for our button and the dropdown list.

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;
}
Enter fullscreen mode Exit fullscreen mode

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.

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
Enter fullscreen mode Exit fullscreen mode

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

dropdown

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. So we will add a ref to that component

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
Enter fullscreen mode Exit fullscreen mode

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 and the complete source code here.

Heroku

Built for developers, by developers.

Whether you're building a simple prototype or a business-critical product, Heroku's fully-managed platform gives you the simplest path to delivering apps quickly — using the tools and languages you already love!

Learn More

Top comments (2)

Collapse
 
aderchox profile image
aderchox

One can do this even without using ref. E.g.:

<ComponentName className={
    `${style.someclass} anotherNonMangledClass`
}/>
Enter fullscreen mode Exit fullscreen mode

and then just use the e.target.closest(".anotherNonMangledClass") to check from children towards parent (in the reverse direction of yours).

Collapse
 
luisaugs profile image
luisaugs

Thanks you! Its was helpfull!

nextjs tutorial video

Youtube Tutorial Series

So you built a Next.js app, but you need a clear view of the entire operation flow to be able to identify performance bottlenecks before you launch. But how do you get started? Get the essentials on tracing for Next.js from @nikolovlazar in this video series 👀

Watch the Youtube series

👋 Kindness is contagious

Engage with a wealth of insights in this thoughtful article, valued within the supportive DEV Community. Coders of every background are welcome to join in and add to our collective wisdom.

A sincere "thank you" often brightens someone’s day. Share your gratitude in the comments below!

On DEV, the act of sharing knowledge eases our journey and fortifies our community ties. Found value in this? A quick thank you to the author can make a significant impact.

Okay