useClickOutside
The useClickOutside
hook is a custom React hook designed to detect interactions outside a specified HTML element. It is particularly useful for implementing dropdowns, modals, or any UI component that requires closing or reacting to outside clicks or interactions.
Props
handler (event: Event) => void
: The callback function that gets triggered when an interaction outside the referenced element is detected..events EventType[]
(Optional): An array of event types to listen for. Defaults to['mousedown']
. Supported values:"mousedown"
,"mouseup"
,"touchstart"
,"touchend"
,"focusin"
,"focusout"
listenCapturing boolean
(Optional): Indicates whether event listeners should use the capturing phase. Defaults to true.
Returns
RefObject<T>
A React ref object that should be attached to the target HTML element you want to monitor.
The Hook
useClickOutside.ts
import { useIsomorphicEffect } from "hooks/useIsomorphicEffect";
import { RefObject, useRef } from "react";
type EventType =
| "mousedown"
| "mouseup"
| "touchstart"
| "touchend"
| "focusin"
| "focusout";
export function useClickOutside<T extends HTMLElement = HTMLElement>(
handler: (event: Event) => void,
events: EventType[] = ["mousedown"],
listenCapturing: boolean = true
): RefObject<T> {
const ref = useRef<T>(null);
useIsomorphicEffect(() => {
function handleClickOutside(event: Event) {
if (typeof window === "undefined") return;
if (ref.current && !ref.current.contains(event.target as Node)) {
handler(event);
}
}
events.forEach((eventType) => {
document.addEventListener(eventType, handleClickOutside, listenCapturing);
});
return () => {
events.forEach((eventType) => {
document.removeEventListener(
eventType,
handleClickOutside,
listenCapturing
);
});
};
}, [handler, events, listenCapturing]);
return ref;
}
Usage
UseClickOutsideDemo.tsx
import React, { useState } from "react";
import { useClickOutside } from "hooks/useClickOutside";
function Dropdown() {
const [isOpen, setIsOpen] = useState(false);
const ref = useClickOutside<HTMLDivElement>(() => {
setIsOpen(false); // Close the dropdown when clicking outside
});
return (
<div>
<button onClick={() => setIsOpen((prev) => !prev)}>
Toggle Dropdown
</button>
{isOpen && (
<div ref={ref} style={{ border: "1px solid black", padding: "10px" }}>
<p>Dropdown Content</p>
</div>
)}
</div>
);
}