Skip to content

Outside Click

hookclickoutsidedismiss

Detect clicks outside a referenced element. Useful for closing dropdowns, popovers, and modals when the user clicks elsewhere.

tsx
const ref = useRef<HTMLDivElement>(null);const triggerRef = useRef<HTMLButtonElement>(null);useOutsideClick(ref, () => setOpen(false), open, [triggerRef], { priority: 2 });

Installation

$pnpm exec dgadd add ui/outside-click
[Installs to]src/hooks/use-outside-click.ts[Item]ui/outside-click

dgadd is not public on npm yet. Until the first release, pack @diffgazer/add from the repository and install that tarball into this app, which is what puts dgadd on pnpm exec.

UI components require Tailwind CSS v4. Local copy mode imports src/styles/styles.css; package mode uses @diffgazer/ui CSS once packages are available.

Parameters

NameTypeDefaultDescription
refrequiredRefObject<HTMLElement | null>Ref to the element that defines the 'inside' boundary. Clicks outside this element trigger the handler.
handlerrequired() => voidCalled when a click occurs outside the referenced element.
enabledbooleantrueWhether the listener is active. Defaults to true. Set to false to temporarily disable detection.
excludeRefsReadonlyArray<RefObject<HTMLElement | null>>Additional refs to exclude from outside-click detection. Clicks on elements within these refs will not trigger the handler. Useful for excluding trigger elements when content renders in a portal.
optionsOverlayStackOptionsFifth positional argument. Its priority sets this outside-pointer layer's overlay-stack precedence. The inside boundary remains ref and the fourth excludeRefs argument.

Returns

voidThis hook does not return a value. It attaches and cleans up capture-phase pointerdown, with capture-phase touchstart and mousedown fallbacks.

Examples

Dismiss Panel

Preview

Notes

Event Type

Uses capture-phase pointerdown when available, with capture-phase touchstart and mousedown fallbacks, to detect outside interactions before the click completes.

Conditional content

Pass the same open state as enabled when the referenced element mounts conditionally. The hook reconciles late ref attachment, node replacement, and owner-document changes after each commit.

Used By

Built into PopoverContent for dismiss-on-outside-click behavior.

Source

Highlighted source loads after this disclosure opens. Browse the source repository.

Event timing

The hook listens in the capture phase so dismissal runs before the later click. Modern documents use pointerdown; documents without Pointer Events install touchstart and mousedown fallbacks with the same capture-phase timing.

Overlay stack options

options is the fifth positional argument, after excludeRefs. Use priority when overlapping dismissal layers cannot be ordered by DOM nesting alone:

tsx
useOutsideClick(panelRef, closePanel, open, [triggerRef], { priority: 2 })

useOutsideClick reads priority from this shared options type. Its first ref and fourth excludeRefs arguments remain the outside-pointer and nested-overlay boundaries. useEscapeKey uses the options object's ref and excludeRefs fields because it has no separate boundary arguments.

Escape dismissal

The same source file also exports useEscapeKey for overlay dismissal stacks that need Escape handling without outside-pointer handling. Both hooks share the same priority and nested-overlay ordering options:

tsx
useEscapeKey((event) => {
  event.preventDefault()
  setOpen(false)
}, open, { ref: panelRef })