Instead of Copy-Pasting That "Click Outside" Snippet, Here's a Better Alternative

Written by thiya11 | Published 2026/03/24
Tech Story Tags: npm | npm-package | nodejs | react | reactjs | reacthooks | javascript | front-end-development

TLDRReact developers often write boilerplate code to detect clicks outside of an element. The code is too complex, so I built a simple hook to do it for them. It's written in TypeScript from the ground up with full type inference.via the TL;DR App

Every React developer has written this code at least once:

useEffect(() => {
  function handleClickOutside(event) {
    if (ref.current && !ref.current.contains(event.target)) {
      setOpen(false);
    }
  }
  document.addEventListener("mousedown", handleClickOutside);
  return () => document.removeEventListener("mousedown", handleClickOutside);
}, [ref]);

You paste it from Stack Overflow. It works. You move on. Then you write it again next week for the modal. Then again, for the dropdown. Then again, for the tooltip.

Sound familiar?

That's exactly why I built @kitsunechaos/use-outside-click.


The Problem

Detecting a click outside an element is one of the most common UI patterns in React:

  • Closing a dropdown when you click elsewhere
  • Dismissing a modal on backdrop click
  • Collapsing a popover, tooltip, or color picker
  • Hiding a mobile navigation drawer

Yet, every time, we write the same boilerplate — or worse, reach for a 6KB library that wraps it in a class component HOC from 2018.

There had to be a better way.


Introducing @kitsunechaos/use-outside-click

A dead-simple React hook that detects clicks outside any element. That's it. No fluff.

npm install @kitsunechaos/use-outside-click

Usage

import { useRef } from "react";
import useOutsideClick from "@kitsunechaos/use-outside-click";

function Dropdown() {
  const ref = useRef(null);
  const [open, setOpen] = useState(false);

  useOutsideClick(ref, () => setOpen(false));

  return (
    <div ref={ref}>
      <button onClick={() => setOpen(true)}>Open</button>
      {open && <ul>{/* dropdown items */}</ul>}
    </div>
  );
}

One import. One ref. One callback. Done.


What Makes It Different

✅ Zero Dependencies

No bloat. No peer dependency warnings. Nothing extra in your node_modules.

✅ Fully Typed

Written in TypeScript from the ground up. Full type inference — no @types/ package needed.

useOutsideClick(ref: RefObject<HTMLElement>, callback: () => void): void

✅ SSR Safe

Works seamlessly with Next.js, Remix, and any server-side rendering setup. No window is not defined errors.

✅ Touch + Mouse Support

Handles both mousedown and touchstart events — works perfectly on mobile devices too.

✅ Tiny Bundle Size

Under 400 bytes gzipped. Your users will never notice it's there.

✅ Supports Multiple Refs

Need to track outside clicks across multiple elements? Supported out of the box.


Real World Example — Dropdown Menu

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

export function DropdownMenu() {
  const ref = useRef<HTMLDivElement>(null);
  const [isOpen, setIsOpen] = useState(false);

  useOutsideClick(ref, () => setIsOpen(false));

  return (
    <div ref={ref} style={{ position: "relative", display: "inline-block" }}>
      <button onClick={() => setIsOpen((prev) => !prev)}>
        Options ▾
      </button>
      {isOpen && (
        <ul style={{ position: "absolute", background: "white", border: "1px solid #eee" }}>
          <li>Edit</li>
          <li>Duplicate</li>
          <li>Delete</li>
        </ul>
      )}
    </div>
  );
}

No more cleanup logic. No more forgotten removeEventListener. Just clean, readable code.


Before vs After

Before — raw boilerplate every time:

// 10+ lines, every single component
useEffect(() => {
  function handleClickOutside(event) {
    if (ref.current && !ref.current.contains(event.target)) {
      onClose();
    }
  }
  document.addEventListener("mousedown", handleClickOutside);
  return () => {
    document.removeEventListener("mousedown", handleClickOutside);
  };
}, []);

After — one line:

useOutsideClick(ref, onClose);

Installation

# npm
npm install @kitsunechaos/use-outside-click

# yarn
yarn add @kitsunechaos/use-outside-click

# pnpm
pnpm add @kitsunechaos/use-outside-click


If this saved you from writing that boilerplate one more time — drop a ⭐ on GitHub. It genuinely helps other developers discover it.

Built with 🦊 by kitsunechaos


Written by thiya11 | Dedicated Full-Stack Developer, specializing in Angular and Node. Enthusiastic about pushing CSS boundaries.
Published by HackerNoon on 2026/03/24