useClickOutside & useEventListener in React
From the React Custom Hooks cheat sheet · Interaction & Lifecycle Hooks · verified Jul 2026
useClickOutside & useEventListener
Dismiss menus/popovers and attach typed event listeners safely
jsx
import { useEffect, useRef, RefObject } from 'react'
function useClickOutside<T extends HTMLElement>(
ref: RefObject<T>,
onOutside: (e: MouseEvent | TouchEvent) => void,
) {
useEffect(() => {
const handler = (e: MouseEvent | TouchEvent) => {
const el = ref.current
if (!el || el.contains(e.target as Node)) return
onOutside(e)
}
document.addEventListener('mousedown', handler)
document.addEventListener('touchstart', handler)
return () => {
document.removeEventListener('mousedown', handler)
document.removeEventListener('touchstart', handler)
}
}, [ref, onOutside])
}
// Usage
function Dropdown() {
const ref = useRef<HTMLDivElement>(null)
const [open, setOpen] = useState(false)
useClickOutside(ref, () => setOpen(false))
return <div ref={ref}>{open && <Menu />}</div>
}💡 Use mousedown (not click) - fires before focus/blur and feels snappier
⚡ The handlerRef pattern avoids re-binding listeners every render
📌 touchstart needs { passive: true } to avoid scroll-blocking warnings
🎯 useEventListener is the typed, cleanup-safe primitive for any DOM event
eventsdomui