useClickOutside
zyeon/use-click-outsideFreeHook
A hook that runs a handler when a pointer interaction lands outside one or more referenced elements.
Install it
npx shadcn@latest add https://ui.zyeon.ai/r/use-click-outside.jsonSource
1"use client"23import * as React from "react"45/** Document events that can be listened for. `pointerdown` alone covers mouse, touch and pen. */6export type ClickOutsideEvent = "pointerdown" | "mousedown" | "click" | "touchstart"78/** Any element ref — `useRef<HTMLDivElement>(null)` can be handed straight in. */9export type ClickOutsideRef = React.RefObject<Element | null>1011export interface UseClickOutsideOptions {12 /** Unbinds the listener (no point sitting on document while the layer is closed). Defaults to true. */13 enabled?: boolean14 /** Which document events to listen for. Defaults to ["pointerdown"]. */15 events?: ClickOutsideEvent[]16}1718/** Module-level constant: the default reuses one array identity, saving a pointless dependency change. */19const DEFAULT_EVENTS: ClickOutsideEvent[] = ["pointerdown"]2021/**22 * Calls `handler` when an interaction lands outside **all** of the given refs. An array is23 * accepted for the classic case of a trigger and a layer being two DOM nodes with no nesting24 * between them (dropdowns, portalled popovers): a press on the trigger must not count as25 * outside, or the button is closed and then reopened and the layer never appears to open.26 *27 * - **SSR safe**: `document` is only touched inside the effect, never during render.28 * - **No listener churn**: `handler` and `refs` live in refs refreshed each render, and29 * `events` is serialised into a string dependency — inline arrows and inline arrays are30 * what consumers actually write, and passing those straight into the dependency array31 * would rebind the document listener on every render.32 * - **Detached nodes**: see the `isConnected` comment in `listener`; that is the trap this33 * hook exists to avoid.34 * - `pointerdown` rather than `click` by default: dismissal happens the moment you press,35 * which feels more direct and sidesteps the drag that starts inside the layer and36 * releases outside it.37 */38export function useClickOutside(39 refs: ClickOutsideRef | ClickOutsideRef[],40 handler: (event: Event) => void,41 options: UseClickOutsideOptions = {},42): void {43 const { enabled = true, events = DEFAULT_EVENTS } = options4445 const handlerRef = React.useRef(handler)46 const refsRef = React.useRef(refs)47 React.useEffect(() => {48 handlerRef.current = handler49 refsRef.current = refs50 })5152 // `events` is usually an array literal written at the call site, so by reference it counts53// … truncated
Files it writes
More from zyeon
All 893 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| useAsyncuse-async | zyeon | Hooks | Free | no deps | |
| useBatteryuse-battery | zyeon | Hooks | Free | no deps | |
| useBroadcastChanneluse-broadcast-channel | zyeon | Hooks | Free | no deps | |
| useClipboardPasteuse-clipboard-paste | zyeon | Hooks | Free | no deps | |
| useControllableStateuse-controllable-state | zyeon | Hooks | Free | no deps | |
| useCookieuse-cookie | zyeon | Hooks | Free | no deps | |
| useCopyToClipboarduse-copy-to-clipboard | zyeon | Hooks | Free | no deps | |
| useCountdownuse-countdown | zyeon | Hooks | Free | no deps |
