Skip to content

useClickOutside

Saurav-TB-Pandey edited this page Aug 10, 2026 · 3 revisions

useClickOutside

A lightweight hook that detects interactions (clicks, touches) occurring outside of one or more specified DOM elements. This is the industry-standard pattern for automatically closing dropdowns, modals, context menus, and tooltips when the user clicks away.

Usage Examples

Basic

Closing a dropdown menu when the user clicks anywhere else on the screen.

import { useState, useRef } from "react";
import { useClickOutside } from "react-hook-lab";

function Dropdown() {
  const [isOpen, setIsOpen] = useState(false);
  const dropdownRef = useRef<HTMLDivElement>(null);

  // Instantly closes the dropdown if a click is detected outside of dropdownRef
  useClickOutside(dropdownRef, () => setIsOpen(false));

  return (
    <div style={{ position: "relative" }}>
      <button onClick={() => setIsOpen(!isOpen)}>Toggle Menu</button>
      
      {isOpen && (
        <div ref={dropdownRef} className="dropdown-menu">
          <a href="#">Profile</a>
          <a href="#">Settings</a>
          <a href="#">Logout</a>
        </div>
      )}
    </div>
  );
}

Common

Listening to multiple refs simultaneously. Useful for a modal where the trigger button and the modal body are technically separate DOM elements, but clicking either shouldn't close the modal.

import { useState, useRef } from "react";
import { useClickOutside } from "react-hook-lab";

function ModalWithExternalTrigger() {
  const [isOpen, setIsOpen] = useState(false);
  const modalRef = useRef<HTMLDivElement>(null);
  const buttonRef = useRef<HTMLButtonElement>(null);

  // Passes an array of refs. Clicking inside ANY of these refs will be ignored.
  useClickOutside([modalRef, buttonRef], () => setIsOpen(false));

  return (
    <div>
      <button ref={buttonRef} onClick={() => setIsOpen(true)}>Open Modal</button>
      
      {isOpen && (
        <div className="modal-overlay">
          <div ref={modalRef} className="modal-content">
            <h2>Important Modal</h2>
            <p>Clicking the overlay will close this.</p>
          </div>
        </div>
      )}
    </div>
  );
}

Advanced

Temporarily disabling the hook for performance, or customizing the specific DOM events it listens to (e.g. tracking mouseup instead of mousedown).

import { useRef } from "react";
import { useClickOutside } from "react-hook-lab";

function AdvancedTooltip({ isVisible, onClose }: { isVisible: boolean, onClose: () => void }) {
  const tooltipRef = useRef<HTMLDivElement>(null);

  useClickOutside(tooltipRef, onClose, {
    // Only attach the DOM listeners if the tooltip is actually visible
    enabled: isVisible, 
    // Listen to strict pointer events instead of generic clicks
    events: ["pointerup"] 
  });

  if (!isVisible) return null;

  return <div ref={tooltipRef}>Tooltip Content</div>;
}

API Reference

Parameters

  • ref
    • Type: RefObject<T> | RefObject<T>[]
    • Description: A single React ref, or an array of refs, pointing to the elements you want to "protect". Clicks inside these elements will NOT trigger the handler.
  • handler
    • Type: (event: Event) => void
    • Description: The callback function to execute when a click occurs outside the ref(s).
  • options (Optional)
    • Type: UseClickOutsideOptions
    • Description: Configuration object.
export interface UseClickOutsideOptions {
  enabled?: boolean; // Default: true. Disables the event listeners if false.
  events?: string[]; // Default: ["mousedown", "touchstart"]. 
}

Return Type

This hook does not return any value.

Core Working

When mounted, useClickOutside attaches global event listeners (by default, mousedown and touchstart) directly to the document.

Whenever one of these events fires, the hook intercepts the native DOM event. It uses the Node.contains(event.target) API to check if the exact element clicked is a child (or the element itself) of any of the provided refs. If the click target is completely independent of your refs, it fires your handler callback. It aggressively cleans up the document listeners upon unmount or when enabled is toggled to false.

Clone this wiki locally