DEV Community

Shin-Young Jung
Shin-Young Jung

Posted on

React Hook: check outside click

When we implement a dropdown or drawer component in React, these components often require to be closed when mouse-clicking either the menu button or outside of the component.

image

To allow this behavior in our custom components, we can create a custom hook that allows us to apply the same behavior whenever we need it.

Here is a simple custom hook that checks if the mouse clicks outside of the current component.

const useCheckOutside = 
(clickOutside: () => void, exceptId?: string) => ...
Enter fullscreen mode Exit fullscreen mode

We named the hook useCheckOutside, and it receives the clickOutside function as a property that allows the parent component to receive the event.

exceptId is an optional property that can be used to ignore the place where we don't want the close behavior when the place is clicked. We need this because usually the menu or the dropdown button is also a part of the outside clicks, and the button's onClick event changes the menu or dropdown's visibility to be visible whereas the outside click changes the visibility to be hidden. The below function describes that the exceptId will be ignored in the mousedown event.

const checkOutsideClick = (event: any) => {
      if (
        ref.current &&
        !ref.current.contains(event.target) &&
        event.target.id !== exceptId
      ) {
        clickOutside();
      }
    };

document.addEventListener('mousedown', checkOutsideClick);
Enter fullscreen mode Exit fullscreen mode

Here is the entire code for the useCheckoutside hook with a simple example of how to use.

import { useEffect, useRef } from 'react';

const useCheckOutside = 
      (clickOutside: () => void, 
       exceptId?: string) => {

  const ref = useRef<any>();

  useEffect(() => {
    const checkOutsideClick = (event: any) => {
      if (
        ref.current &&
        !ref.current.contains(event.target) &&
        event.target.id !== exceptId
      ) {
        clickOutside();
      }
    };
    document.addEventListener('mousedown', checkOutsideClick);
    return () => {
      document.removeEventListener('mousedown', checkOutsideClick);
    };
  }, [clickOutside]);

  return ref;
};

export default useCheckOutside;
Enter fullscreen mode Exit fullscreen mode

const handleOutsideClick = () => {
     setOpen(false);
}

const ref = useCheckOutside(handleOutsideClick, "buttonId");

return <>
         <button id="buttonId" type="button" 
                 onClick={(e) => {
                   setOpen(true)
                 }
          >
          Menu
          </button>

          {open && <Menu ref={ref} />}
        </>
Enter fullscreen mode Exit fullscreen mode

Top comments (0)