useOnClickOutside


Custom hook that handles clicks outside a specified element.

Usage

import { useRef } from 'react'

import { useOnClickOutside } from 'usehooks-ts'

export default function Component() {
  const ref = useRef(null)

  const handleClickOutside = () => {
    // Your custom logic here
    console.log('clicked outside')
  }

  const handleClickInside = () => {
    // Your custom logic here
    console.log('clicked inside')
  }

  useOnClickOutside(ref, handleClickOutside)

  return (
    <button
      ref={ref}
      onClick={handleClickInside}
      style={{ width: 200, height: 200, background: 'cyan' }}
    />
  )
}

API

useOnClickOutside<T>(ref, handler, eventType?, eventListenerOptions?): void

Custom hook that handles clicks outside a specified element.

Type parameters

NameTypeDescription
Textends HTMLElement = HTMLElementThe type of the element's reference.

Parameters

NameTypeDefault valueDescription
refRefObject<T> | RefObject<T>[]undefinedThe React ref object(s) representing the element(s) to watch for outside clicks.
handler(event: MouseEvent | FocusEvent | TouchEvent) => voidundefinedThe callback function to be executed when a click outside the element occurs.
eventType?EventType'mousedown'The mouse event type to listen for (optional, default is 'mousedown').
eventListenerOptions?AddEventListenerOptions{}The options object to be passed to the addEventListener method (optional).

Returns

void

Type aliases

Ƭ EventType: "mousedown" | "mouseup" | "touchstart" | "touchend" | "focusin" | "focusout"

Supported event types.

Hook

import type { RefObject } from 'react'

import { useEventListener } from 'usehooks-ts'

type EventType =
  | 'mousedown'
  | 'mouseup'
  | 'touchstart'
  | 'touchend'
  | 'focusin'
  | 'focusout'

export function useOnClickOutside<T extends HTMLElement = HTMLElement>(
  ref: RefObject<T> | RefObject<T>[],
  handler: (event: MouseEvent | TouchEvent | FocusEvent) => void,
  eventType: EventType = 'mousedown',
  eventListenerOptions: AddEventListenerOptions = {},
): void {
  useEventListener(
    eventType,
    event => {
      const target = event.target as Node

      // Do nothing if the target is not connected element with document
      if (!target || !target.isConnected) {
        return
      }

      const isOutside = Array.isArray(ref)
        ? ref
            .filter(r => Boolean(r.current))
            .every(r => r.current && !r.current.contains(target))
        : ref.current && !ref.current.contains(target)

      if (isOutside) {
        handler(event)
      }
    },
    undefined,
    eventListenerOptions,
  )
}