Create a Custom React Hook to Detect Outside Clicks

Managing dropdowns, modals, or other pop-up elements often requires detecting clicks outside these elements to close them.

Since it's a common problem, a clean and reusable solution is to create a custom React hook.

This article will guide you through creating a custom hook to detect outside clicks and touch events effectively.

How to

Create a new file useOutsideClick.js in your project with the following (don't worry I'll explain the code after):

import { useEffect, useRef } from 'react';

function useOutsideClick(callback) {
  const ref = useRef();

  useEffect(() => {
    function handleClickOutside(event) {
      if (ref.current && !ref.current.contains(event.target)) {
        callback();
      }
    }

    document.addEventListener('mousedown', handleClickOutside);
    document.addEventListener('touchend', handleClickOutside);

    return () => {
      document.removeEventListener('mousedown', handleClickOutside);
      document.removeEventListener('touchend', handleClickOutside);
    };
  }, [callback]);

  return ref;
}

export default useOutsideClick;

What doe this do?

  • We use a ref to track the DOM element.
  • The useEffect hook adds an event listener to detect clicks outside the referenced element. We listen to mousedown for people on computers and touchend for touch screens.
  • The handleClickOutside function checks if the click is outside the element, triggering the callback if it is.
  • The cleanup function removes the event listener when the component unmounts.

Now, let's use this custom hook in a component, such as a dropdown menu:

import React, { useState } from 'react';
import useOutsideClick from './useOutsideClick';

function Dropdown() {
  const [isOpen, setIsOpen] = useState(false);
  const ref = useOutsideClick(() => setIsOpen(false));

  return (
    <div ref={ref} className="dropdown-container">
      <button onClick={() => setIsOpen(!isOpen)}>Toggle Dropdown</button>
      {isOpen && (
        <div className="dropdown-menu">
          <p>Dropdown Item 1</p>
          <p>Dropdown Item 2</p>
          <p>Dropdown Item 3</p>
        </div>
      )}
    </div>
  );
}

export default Dropdown;

In this component:

  • We manage the dropdown's open state with isOpen and setIsOpen.
  • We use the useOutsideClick hook, passing a callback to set the open state to false so that we auto-magically update our UI when we detect the outside click. The ref from useOutsideClick is attached to the dropdown's container element, which infers which element it is listening to.
Reactjs
Avatar for Niall Maher

Written by Niall Maher

Founder of Codú - The web developer community! I've worked in nearly every corner of technology businesses; Lead Developer, Software Architect, Product Manager, CTO and now happily a Founder.

Loading

Fetching comments

Hey! 👋

Got something to say?

or to leave a comment.