react
useClickOutside Hook
Detect clicks outside an element - perfect for dropdowns, modals, and popover menus.
#hooks
#events
#ui
A hook to detect when users click outside a specified element.
useClickOutside Hook
import { useEffect, useRef, RefObject } from 'react';
function useClickOutside<T extends HTMLElement>(
handler: () => void
): RefObject<T> {
const ref = useRef<T>(null);
useEffect(() => {
const listener = (event: MouseEvent | TouchEvent) => {
const el = ref.current;
if (!el || el.contains(event.target as Node)) {
return;
}
handler();
};
document.addEventListener('mousedown', listener);
document.addEventListener('touchstart', listener);
return () => {
document.removeEventListener('mousedown', listener);
document.removeEventListener('touchstart', listener);
};
}, [handler]);
return ref;
}
export default useClickOutside;
Usage - Dropdown Menu
function Dropdown() {
const [isOpen, setIsOpen] = useState(false);
const dropdownRef = useClickOutside<HTMLDivElement>(() => setIsOpen(false));
return (
<div ref={dropdownRef} className="relative">
<button onClick={() => setIsOpen(!isOpen)}>
Menu ▾
</button>
{isOpen && (
<div className="absolute top-full mt-2 bg-white shadow-lg rounded-lg">
<a href="/profile">Profile</a>
<a href="/settings">Settings</a>
<a href="/logout">Logout</a>
</div>
)}
</div>
);
}
Usage - Modal
function Modal({ isOpen, onClose, children }) {
const modalRef = useClickOutside<HTMLDivElement>(onClose);
if (!isOpen) return null;
return (
<div className="fixed inset-0 bg-black/50 flex items-center justify-center">
<div ref={modalRef} className="bg-white p-6 rounded-xl max-w-lg">
{children}
</div>
</div>
);
}
With Multiple Refs (Escape Key Support)
function useClickOutside<T extends HTMLElement>(
handler: () => void,
enableEscape: boolean = true
): RefObject<T> {
const ref = useRef<T>(null);
useEffect(() => {
const clickListener = (e: MouseEvent | TouchEvent) => {
if (!ref.current?.contains(e.target as Node)) handler();
};
const keyListener = (e: KeyboardEvent) => {
if (enableEscape && e.key === 'Escape') handler();
};
document.addEventListener('mousedown', clickListener);
document.addEventListener('touchstart', clickListener);
document.addEventListener('keydown', keyListener);
return () => {
document.removeEventListener('mousedown', clickListener);
document.removeEventListener('touchstart', clickListener);
document.removeEventListener('keydown', keyListener);
};
}, [handler, enableEscape]);
return ref;
}
Common uses:
- Dropdown menus
- Modal dialogs
- Popover tooltips
- Search autocomplete
- Date pickers