UseOnClickOutside : Custom hook to detect the mouse click on outside (typescript)
React Hooks had changed the evolution of React to the great extent. One of the feature of the react hooks is custom hooks. What is custom hooks? Custom hooks are hooks which is defined by us. Sound interesting, Right. In simple words, We, the developers can define the hooks and use the hooks based on our functionality. In this blog, i am going to create a custom hook called useOnClickOutside.
useOnClickOutside is a custom hook which is used to detect whenever the mouse click happens outside the specified element. useOnClickOutside requires two parameters, reference of the element (Ref) and callback function to be executed when the event occurs (handler).
const useOnClickOutside = <T extends HTMLElement = HTMLElement>(
ref: RefObject<T>,
handler: (event: Event) => void,
) => {}
Next step is to add the mouse down and touch start event listener to the document. Whenever the click event or touch event occurs in the document, they will capture the event. the Touch start event listener is to handle the cases in mobile phones or touch devices.
document.addEventListener('mousedown', listener);
document.addEventListener('touchstart', listener);
listener is used to handle the mouse down and touch start events. In the listener, we need to check if the click event occurs on the specified element or not. If the event occurs on the specified element, the callback will not be called. If the event occurs outside the specified element, the callback will be called.
const listener = (event: Event) => {
const el = ref?.current;
if (!el) {
return;
}
handler(event); // Call the handler only if the click is outside of the element passed.
};
We need to remove the event listeners when the component gets unmounted. We are doing this to improve the performance The final code of the useOnClickOutside will be like,
import { useEffect, RefObject } from 'react';
type Event = MouseEvent | TouchEvent;
const useOnClickOutside = <T extends HTMLElement = HTMLElement>(
ref: RefObject<T>,
handler: (event: Event) => void,
) => {
useEffect(() => {
const listener = (event: Event) => {
const el = ref?.current;
if (!el || el.contains((event?.target as Node) || null)) {
return;
}
handler(event); // Call the handler only if the click is outside of the element passed.
};
document.addEventListener('mousedown', listener);
document.addEventListener('touchstart', listener);
return () => {
document.removeEventListener('mousedown', listener);
document.removeEventListener('touchstart', listener);
};
}, [ref, handler]); // Reload only if ref or handler changes
};
I have done a simple demo with the useOnClickOutside hook. Please check out the below link.