or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/npm-chakra-ui--react-use-outside-click

React hook for detecting clicks outside of specified elements, commonly used in dialogs and popovers

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/@chakra-ui/react-use-outside-click@2.2.x

To install, run

npx @tessl/cli install tessl/npm-chakra-ui--react-use-outside-click@2.2.0

index.mddocs/

@chakra-ui/react-use-outside-click

A React hook for detecting clicks outside of specified elements. Commonly used in components like dialogs, popovers, modals, and dropdowns to implement automatic closing behavior when users click elsewhere on the page.

Package Information

  • Package Name: @chakra-ui/react-use-outside-click
  • Package Type: npm
  • Language: TypeScript
  • Installation: npm install @chakra-ui/react-use-outside-click

Core Imports

import { useOutsideClick, type UseOutsideClickProps } from "@chakra-ui/react-use-outside-click";

For CommonJS:

const { useOutsideClick } = require("@chakra-ui/react-use-outside-click");

Dependencies:

// Internal dependency (automatically included)
import { useCallbackRef } from "@chakra-ui/react-use-callback-ref";

Basic Usage

import React, { useRef, useState } from "react";
import { useOutsideClick } from "@chakra-ui/react-use-outside-click";

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

  useOutsideClick({
    ref: modalRef,
    handler: () => setIsOpen(false),
  });

  if (!isOpen) return null;

  return (
    <div className="overlay">
      <div ref={modalRef} className="modal">
        <h2>Modal Content</h2>
        <p>Click outside to close this modal</p>
      </div>
    </div>
  );
}

Capabilities

Outside Click Detection

Detects clicks occurring outside specified DOM elements and executes a callback handler. Uses a sophisticated pointer event strategy that handles mouse, touch, and pointer events with proper state tracking and safeguards against emulated mouse events on touch devices.

/**
 * React hook for detecting clicks outside specified elements
 * @param props - Configuration object for the hook
 */
function useOutsideClick(props: UseOutsideClickProps): void;

interface UseOutsideClickProps {
  /** Whether the hook is enabled (defaults to true) */
  enabled?: boolean;
  /** Reference to a DOM element to detect outside clicks for */
  ref: React.RefObject<HTMLElement>;
  /** Function invoked when a click is triggered outside the referenced element */
  handler?: (e: Event) => void;
}

Key Features:

  • Advanced event handling: Uses pointer tracking with mousedown, mouseup, touchstart, and touchend events
  • State-based tracking: Maintains internal state to track pointer down and ignore emulated mouse events
  • Emulated event prevention: Handles touch device quirks by preventing duplicate mouse events through ignoreEmulatedMouseEvents flag
  • Configurable enable/disable: Can be dynamically enabled or disabled via the enabled prop
  • Proper cleanup: Automatically removes event listeners when the component unmounts or when disabled
  • React ref integration: Works seamlessly with React's ref system
  • Document-level listeners: Uses document-level event delegation for optimal performance
  • Owner document awareness: Handles elements across different document contexts

Usage Examples:

import React, { useRef, useState } from "react";
import { useOutsideClick } from "@chakra-ui/react-use-outside-click";

// Basic popover with outside click to close
function Popover({ children, content }: { children: React.ReactNode; content: string }) {
  const [isVisible, setIsVisible] = useState(false);
  const popoverRef = useRef<HTMLDivElement>(null);

  useOutsideClick({
    ref: popoverRef,
    handler: () => setIsVisible(false),
    enabled: isVisible, // Only listen when popover is visible
  });

  return (
    <div className="popover-container">
      <button onClick={() => setIsVisible(!isVisible)}>
        {children}
      </button>
      {isVisible && (
        <div ref={popoverRef} className="popover">
          {content}
        </div>
      )}
    </div>
  );
}

// Dropdown menu with outside click handling
function DropdownMenu() {
  const [isOpen, setIsOpen] = useState(false);
  const menuRef = useRef<HTMLUListElement>(null);

  useOutsideClick({
    ref: menuRef,
    handler: (event) => {
      console.log("Clicked outside at:", event.target);
      setIsOpen(false);
    },
  });

  return (
    <div className="dropdown">
      <button onClick={() => setIsOpen(!isOpen)}>
        Menu {isOpen ? "▲" : "▼"}
      </button>
      {isOpen && (
        <ul ref={menuRef} className="menu">
          <li>Option 1</li>
          <li>Option 2</li>
          <li>Option 3</li>
        </ul>
      )}
    </div>
  );
}

// Conditional hook usage
function ConditionalOutsideClick({ shouldListen }: { shouldListen: boolean }) {
  const ref = useRef<HTMLDivElement>(null);

  useOutsideClick({
    ref,
    handler: () => console.log("Outside click detected"),
    enabled: shouldListen, // Dynamically enable/disable
  });

  return (
    <div ref={ref}>
      Content that {shouldListen ? "listens for" : "ignores"} outside clicks
    </div>
  );
}

// Advanced usage with event details
function AdvancedOutsideClick() {
  const [isOpen, setIsOpen] = useState(false);
  const ref = useRef<HTMLDivElement>(null);

  useOutsideClick({
    ref,
    handler: (event) => {
      // Access event details for advanced handling
      console.log("Event type:", event.type);
      console.log("Event target:", event.target);
      console.log("Timestamp:", event.timeStamp);
      setIsOpen(false);
    },
    enabled: isOpen, // Only listen when open
  });

  return (
    <div>
      <button onClick={() => setIsOpen(true)}>Open Panel</button>
      {isOpen && (
        <div ref={ref} style={{ border: "1px solid black", padding: "20px" }}>
          Click outside to close
        </div>
      )}
    </div>
  );
}

Implementation Details:

The hook uses sophisticated internal logic:

  • Pointer state tracking: Maintains isPointerDown flag to track pointer interaction state
  • Event sequence validation: Only triggers handler when pointer down followed by pointer up occurs outside
  • Touch event handling: Sets ignoreEmulatedMouseEvents flag on touch end to prevent duplicate events
  • Document validation: Uses isValidEvent helper to ensure events occur on elements within the document
  • Owner document resolution: Resolves the appropriate document context for event listener attachment

Error Handling:

The hook gracefully handles edge cases:

  • Invalid or null refs (no event listeners attached, handled by isValidEvent)
  • Events on elements not in the document (filtered out by document containment check)
  • Touch events followed by emulated mouse events (deduplicated via ignoreEmulatedMouseEvents)
  • Component unmounting during event handling (cleaned up automatically via useEffect cleanup)
  • Multiple rapid interactions (state tracking prevents incorrect triggers)

Internal Helper Functions:

/**
 * Validates if an event should trigger the outside click handler
 * @param event - The DOM event to validate
 * @param ref - React ref to the element being monitored
 * @returns boolean indicating if the event is valid for outside click
 */
function isValidEvent(event: Event, ref: React.RefObject<HTMLElement>): boolean;

/**
 * Gets the owner document for a given DOM element
 * @param node - The DOM element to get the document for
 * @returns The owner document or global document as fallback
 */
function getOwnerDocument(node?: Element | null): Document;

Event Handling Sequence:

  1. Pointer Down Phase: mousedown/touchstart events set isPointerDown = true if outside target
  2. Pointer Up Phase: mouseup/touchend events trigger handler if isPointerDown is true and event is still outside
  3. Touch Event Handling: touchend sets ignoreEmulatedMouseEvents = true to prevent duplicate mouseup handling
  4. Validation: Each event is validated through isValidEvent to ensure proper document containment

Platform Compatibility:

  • Environment: Browser-only (requires DOM APIs)
  • React Version: Requires React 18+
  • TypeScript: Full TypeScript support with complete type definitions
  • Touch Devices: Optimized handling for mobile/tablet interactions with emulated event prevention
  • Event Delegation: Uses document-level event listeners for optimal performance
  • Cross-platform: Works across different document contexts and iframe boundaries