DOM
useClickOutside
Runs a callback on outside click.
Demo
live · imported from hookli
- menu
- closed
- last event
- nothing yet
Open the menu, then click anywhere outside it.
import { useRef, useState } from "react";
import { useClickOutside } from "hookli";
export function Demo() {
const menuRef = useRef<HTMLDivElement>(null);
const [open, setOpen] = useState(false);
useClickOutside(menuRef, () => setOpen(false));
return (
<div ref={menuRef}>
<button onClick={() => setOpen((prev) => !prev)}>Actions</button>
{open && (
<ul role="menu">
<li>Rename</li>
<li>Duplicate</li>
</ul>
)}
</div>
);
}Usage
import { useRef, useState } from "react";
import { useClickOutside } from "hookli";
export function Demo() {
const menuRef = useRef<HTMLDivElement>(null);
const [open, setOpen] = useState(false);
useClickOutside(menuRef, () => setOpen(false));
return (
<div ref={menuRef}>
<button onClick={() => setOpen((prev) => !prev)}>Actions</button>
{open && (
<ul role="menu">
<li>Rename</li>
<li>Duplicate</li>
</ul>
)}
</div>
);
}API
useClickOutside<T extends HTMLElement>(ref: RefObject<T>, callback: () => void): voidParameters
| Name | Type | Default | Description |
|---|---|---|---|
| ref | RefObject<T> | — | Ref attached to the element that counts as inside — clicks within it (or its children) never fire the callback. |
| callback | () => void | — | Called on every mousedown outside the ref'd element — even while your UI is closed, so guard inside the callback if needed. |
Returns
This hook returns nothing.
Hook
The implementation, straight from hookli. Copy it, or install the package.
import { Ref, useEffect } from "react";
type ClickOutsideCallback = () => void;
export const useClickOutside = <T extends HTMLElement>(
ref: Ref<T>,
callback: ClickOutsideCallback,
) => {
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (
ref &&
"current" in ref &&
!ref.current?.contains(event.target as Node)
) {
callback();
}
};
document.addEventListener("mousedown", handleClickOutside);
return () => {
document.removeEventListener("mousedown", handleClickOutside);
};
}, [ref, callback]);
};