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 tomousedown
for people on computers andtouchend
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
andsetIsOpen
. - We use the
useOutsideClick
hook, passing a callback to set the open state tofalse
so that we auto-magically update our UI when we detect the outside click. Theref
fromuseOutsideClick
is attached to the dropdown's container element, which infers which element it is listening to.