Detect if clicked outside the component in React

react handle outside component click

Many times when we create dropdown or pop-over component in react, we want to close it whenever we click outside it.

To do this either we can create a reference to the element or create a custom useClickedOutside() hook in react.

Assign a reference to the element.

Using the useRef hook we can create a reference to the element in react and pull that element as an object.

import React, { useState, useEffect, useRef } from "react";

const dropdown = () => {
  const [active, setActive] = useState(false);
  const dropdownAreaRef = useRef(null);

  return(
   <div className={active ? 'active' : ''} ref={dropdownAreaRef}>
     Drop Down
   </div>
  );
}

Register the click event on document.

In-order to close the dropdown anytime we click outside it, we have to attach the event listener on the whole document.

We will need to use the useEffect to assign the event listener when the component is mounted.

useEffect(() => {
    //Assign click handler to listen the click to close the dropdown when clicked outside
    document.addEventListener("click", handleClickOutside);

    return () => {
      //Remove the listener
      document.removeEventListener("click", handleClickOutside);
    };
  }, []);

The return function will remove the listener when the component will be unmounted.

Now, whenever there is a click on the DOM, handleClickOutside function will be called. Inside that function we can check if the current element which is clicked does not contains the dropdown element in its path (ancestry) then update the state.

To get the dropdown element, we will use the dropdownAreaRef variable, which we had assigned as reference at the beginning.

Each reference variable returns the current element in the current object thus we are using it.

  const handleClickOutside = (event) => {
    const path = event.path || (event.composedPath && event.composedPath());

    if (!path.includes(dropdownAreaRef.current)) {
      setActive(false);
    }
  };

Some browser supports path while some support composedPath thus we use both.

import React, { useState, useEffect, useRef } from "react";

const dropdown = () => {
  const [active, setActive] = useState(false);
  const dropdownAreaRef = useRef(null);
  
  useEffect(() => {
    //Assign click handler to listen the click to close the dropdown when clicked outside
    document.addEventListener("click", handleClickOutside);

    return () => {
      //Remove the listener
      document.removeEventListener("click", handleClickOutside);
    };
  }, []);

  const handleClickOutside = (event) => {
    const path = event.path || (event.composedPath && event.composedPath());

    if (!path.includes(dropdownAreaRef.current)) {
      setActive(false);
    }
  };

  return(
   <div className={active ? 'active' : ''} ref={dropdownAreaRef}>
     Drop Down
   </div>
  );
}

There are many components that needs to detect if the user has clicked outside or not, for example,
1. Functional modal component in Reactjs
2. Create a lightbox (modal-image-gallery) in Reactjs