useClickAway
A hook that allows to handle click events outside of the specified element.
Example
import { useRef, useState } from "react";
import useClickAway from "@/hooks/useClickAway";
export default function UseClickAwayExample() {
const ref = useRef(null);
const [count, setCount] = useState(0);
useClickAway(ref, () => {
setCount(count + 1);
});
return (
<div className="flex flex-col items-center justify-center gap-4 p-4 text-ctp-text">
<p>Click outside the box to see the alert</p>
<div className="rounded-lg bg-ctp-surface1 p-4" ref={ref}>
<p>Click away</p>
</div>
<p>Click away count: {count}</p>
</div>
);
}
Code
import { useEffect, useRef } from "react";
import type { RefObject } from "react";
const defaultEvents = ["mousedown", "touchstart"];
/**
* A hook that allows to handle click events outside of the specified element.
* @param {RefObject<HTMLElement | null>} ref - The reference to the element that should be clicked outside.
* @param {(event: E) => void} onClickAway - The callback function to be called when the click event occurs outside of the specified element.
* @param {string[]} events - An array of event names to listen for.
*/
const useClickAway = <E extends Event = Event>(
ref: RefObject<HTMLElement | null>,
onClickAway: (event: E) => void,
events: string[] = defaultEvents,
) => {
const savedCallback = useRef(onClickAway);
useEffect(() => {
savedCallback.current = onClickAway;
}, [onClickAway]);
useEffect(() => {
const handler = (event: any) => {
const { current: el } = ref;
el && !el.contains(event.target) && savedCallback.current(event);
};
for (const eventName of events) {
window.addEventListener(eventName, handler);
}
return () => {
for (const eventName of events) {
window.removeEventListener(eventName, handler);
}
};
}, [events, ref]);
};
export default useClickAway;