npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@usefy/use-click-any-where

v0.2.4

Published

A React hook for detecting document-wide click events

Readme


Overview

@usefy/use-click-any-where detects clicks anywhere on the document and calls your handler. Perfect for closing dropdowns, modals, context menus, or any component that should respond to outside clicks.

Part of the @usefy ecosystem — a collection of production-ready React hooks designed for modern applications.

Why use-click-any-where?

  • Zero Dependencies — Pure React implementation with no external dependencies
  • TypeScript First — Full type safety with exported interfaces
  • Conditional Activation — Enable/disable via the enabled option
  • Event Capture Support — Choose between capture and bubble phase
  • Passive Listeners — Performance-optimized with passive listeners by default
  • Handler Stability — No re-registration when handler changes
  • SSR Compatible — Works seamlessly with Next.js, Remix, and other SSR frameworks
  • Lightweight — Minimal bundle footprint (~200B minified + gzipped)
  • Well Tested — Comprehensive test coverage with Vitest

Installation

# npm
npm install @usefy/use-click-any-where

# yarn
yarn add @usefy/use-click-any-where

# pnpm
pnpm add @usefy/use-click-any-where

Peer Dependencies

This package requires React 18 or 19:

{
  "peerDependencies": {
    "react": "^18.0.0 || ^19.0.0"
  }
}

Quick Start

import { useClickAnyWhere } from "@usefy/use-click-any-where";

function ClickTracker() {
  const [lastClick, setLastClick] = useState({ x: 0, y: 0 });

  useClickAnyWhere((event) => {
    setLastClick({ x: event.clientX, y: event.clientY });
  });

  return (
    <div>
      Last click: ({lastClick.x}, {lastClick.y})
    </div>
  );
}

API Reference

useClickAnyWhere(handler, options?)

A hook that listens for document-wide click events.

Parameters

| Parameter | Type | Description | | --------- | ----------------------------- | ------------------------------------------------ | | handler | (event: MouseEvent) => void | Callback function called on every document click | | options | UseClickAnyWhereOptions | Configuration options |

Options

| Option | Type | Default | Description | | --------- | --------- | ------- | ------------------------------------------ | | enabled | boolean | true | Whether the event listener is active | | capture | boolean | false | Use event capture phase instead of bubble | | passive | boolean | true | Use passive event listener for performance |

Returns

void


Examples

Close Dropdown on Outside Click

import { useClickAnyWhere } from "@usefy/use-click-any-where";
import { useRef, useState } from "react";

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

  useClickAnyWhere(
    (event) => {
      // Close if clicked outside the dropdown
      if (
        dropdownRef.current &&
        !dropdownRef.current.contains(event.target as Node)
      ) {
        setIsOpen(false);
      }
    },
    { enabled: isOpen }
  );

  return (
    <div ref={dropdownRef}>
      <button onClick={() => setIsOpen(!isOpen)}>Toggle Menu</button>
      {isOpen && (
        <ul className="dropdown-menu">
          <li>Option 1</li>
          <li>Option 2</li>
          <li>Option 3</li>
        </ul>
      )}
    </div>
  );
}

Modal with Click Outside to Close

import { useClickAnyWhere } from "@usefy/use-click-any-where";
import { useRef } from "react";

function Modal({ isOpen, onClose, children }: ModalProps) {
  const modalRef = useRef<HTMLDivElement>(null);

  useClickAnyWhere(
    (event) => {
      if (
        modalRef.current &&
        !modalRef.current.contains(event.target as Node)
      ) {
        onClose();
      }
    },
    { enabled: isOpen }
  );

  if (!isOpen) return null;

  return (
    <div className="modal-overlay">
      <div ref={modalRef} className="modal-content">
        {children}
      </div>
    </div>
  );
}

Context Menu

import { useClickAnyWhere } from "@usefy/use-click-any-where";
import { useState } from "react";

function ContextMenu() {
  const [menu, setMenu] = useState<{ x: number; y: number } | null>(null);

  // Close menu on any click
  useClickAnyWhere(() => setMenu(null), { enabled: menu !== null });

  const handleContextMenu = (e: React.MouseEvent) => {
    e.preventDefault();
    setMenu({ x: e.clientX, y: e.clientY });
  };

  return (
    <div onContextMenu={handleContextMenu} className="context-area">
      Right-click anywhere
      {menu && (
        <div
          className="context-menu"
          style={{ position: "fixed", left: menu.x, top: menu.y }}
        >
          <button>Cut</button>
          <button>Copy</button>
          <button>Paste</button>
        </div>
      )}
    </div>
  );
}

Click Coordinate Logger

import { useClickAnyWhere } from "@usefy/use-click-any-where";
import { useState } from "react";

function ClickLogger() {
  const [clicks, setClicks] = useState<
    Array<{ x: number; y: number; time: Date }>
  >([]);

  useClickAnyWhere((event) => {
    setClicks((prev) => [
      ...prev.slice(-9), // Keep last 10 clicks
      { x: event.clientX, y: event.clientY, time: new Date() },
    ]);
  });

  return (
    <div>
      <h3>Recent Clicks</h3>
      <ul>
        {clicks.map((click, i) => (
          <li key={i}>
            ({click.x}, {click.y}) at {click.time.toLocaleTimeString()}
          </li>
        ))}
      </ul>
    </div>
  );
}

With Capture Phase

import { useClickAnyWhere } from "@usefy/use-click-any-where";

function CapturePhaseHandler() {
  // Handle click before it reaches any element
  useClickAnyWhere(
    (event) => {
      console.log("Click captured (before bubble):", event.target);
    },
    { capture: true }
  );

  return <div>Clicks are captured in capture phase</div>;
}

Tooltip Dismissal

import { useClickAnyWhere } from "@usefy/use-click-any-where";
import { useState, useRef } from "react";

function TooltipTrigger({ content }: { content: string }) {
  const [showTooltip, setShowTooltip] = useState(false);
  const triggerRef = useRef<HTMLButtonElement>(null);

  useClickAnyWhere(
    (event) => {
      if (
        triggerRef.current &&
        !triggerRef.current.contains(event.target as Node)
      ) {
        setShowTooltip(false);
      }
    },
    { enabled: showTooltip }
  );

  return (
    <div className="tooltip-container">
      <button ref={triggerRef} onClick={() => setShowTooltip(!showTooltip)}>
        Show Info
      </button>
      {showTooltip && <div className="tooltip">{content}</div>}
    </div>
  );
}

TypeScript

This hook is written in TypeScript with exported types.

import {
  useClickAnyWhere,
  type UseClickAnyWhereOptions,
  type ClickAnyWhereHandler,
} from "@usefy/use-click-any-where";

// Handler type
const handleClick: ClickAnyWhereHandler = (event) => {
  console.log("Clicked at:", event.clientX, event.clientY);
};

// Options type
const options: UseClickAnyWhereOptions = {
  enabled: true,
  capture: false,
  passive: true,
};

useClickAnyWhere(handleClick, options);

Testing

This package maintains comprehensive test coverage to ensure reliability and stability.

Test Coverage

📊 View Detailed Coverage Report (GitHub Pages)

Test Categories

  • Call handler when document is clicked
  • Pass MouseEvent with correct properties
  • Handle multiple clicks
  • Register event listener on mount
  • Not call handler when enabled is false
  • Not register event listener when disabled
  • Toggle listener when enabled changes
  • Default enabled to true
  • Not re-register listener when handler changes
  • Call the latest handler after update

License

MIT © mirunamu

This package is part of the usefy monorepo.