Skip to content

use-outside-click

A React hook that detects outside click for specified element and triggers the given callback.

TIP

Perfect for implementing modals, dropdowns and other UI components that need to be closed when users click outside of them.

Features

  • Precise trigger: Precise outside click detection
  • Performance: Optimized with capture phase events
  • Underlying hook: At its core, it uses useEventListener hook

Parameters

ParameterTypeRequiredDefault ValueDescription
targetEvTarget-Function that returns the target element or null
handlerEvHandlerundefinedCallback executed on outside click
optionsEvOptionsundefinedEvent listener options and feature flags

Standard AddEventListenerOptions

PropertyTypeDefaultDescription
capturebooleanfalseIf true, the listener will be triggered during the capture phase
oncebooleanfalseIf true, the listener will be automatically removed after being triggered once
passivebooleanfalseIf true, indicates that the function will never call preventDefault()
signalAbortSignalundefinedAn AbortSignal that can be used to remove the event listener

Custom Options

PropertyTypeDefaultDescription
shouldInjectEventboolean | anytrueControls whether the event listener should be attached. When false, the event listener is not added

Type Definitions

Details
tsx
type EvTarget = () => EventTarget | null
type EvHandler = (event: DocumentEventMap['click']) => void

interface EvOptions extends AddEventListenerOptions {
   // Standard AddEventListenerOptions:
   capture?: boolean
   once?: boolean
   passive?: boolean
   signal?: AbortSignal

   // Custom option:
   shouldInjectEvent?: boolean | any // Controls whether the event should be attached
}

Return Value(s)

This hook does not return anything.

Common Use Cases

  • Modal dialogs - Close when clicking backdrop
  • Dropdown menus - Hide when clicking elsewhere
  • Context menus - Dismiss on outside click

Usage Examples

ts
import { useRef, useState } from 'react'
import { useOutsideClick } from 'classic-react-hooks'

function Modal() {
   const [isOpen, setIsOpen] = useState(false)
   const modalRef = useRef<HTMLDivElement>(null)

   useOutsideClick({
      target: () => modalRef.current,
      handler: () => setIsOpen(false),
   })

   if (!isOpen) {
      return <button onClick={() => setIsOpen(true)}>Open Modal</button>
   }

   return (
      <div className='modal-overlay'>
         <div ref={modalRef} class='modal-content bg-white p-8 rounded-lg shadow-md'>
            <h2>Modal Title</h2>
            <p>Click outside this modal to close it.</p>
            <button onClick={() => setIsOpen(false)}>Close</button>
         </div>
      </div>
   )
}

Conditional Outside Click

Example
ts
function ConditionalOutsideClick() {
   const [isModalOpen, setIsModalOpen] = useState(false)
   const [isPinned, setIsPinned] = useState(false)
   const modalRef = useRef<HTMLDivElement>(null)

   useOutsideClick({
      target: () => modalRef.current,
      handler: () => {
         // Only close if not pinned
         if (!isPinned) {
            setIsModalOpen(false)
         }
      },
   })

   return (
      <div>
         {isModalOpen && (
            <div ref={modalRef}>
               <button onClick={() => setIsPinned(!isPinned)}>{isPinned ? 'Unpin' : 'Pin'} Modal</button>
               <p>Modal content</p>
            </div>
         )}
      </div>
   )
}

Dynamic Target

Example
ts
function DynamicTarget() {
   const [activeElement, setActiveElement] = useState<HTMLElement | null>(null)

   useOutsideClick({
      target: () => activeElement,
      handler: () => {
         console.log('Clicked outside active element')
         setActiveElement(null)
      },
   })

   const makeActive = (element: HTMLElement) => {
      setActiveElement(element)
   }

   return (
      <div>
         <div onClick={(e) => makeActive(e.currentTarget)} className='p-5 bg-gray-100 m-2.5'>
            Click to make active
         </div>
      </div>
   )
}