Skip to content

bgunnarsson/click-outside

Repository files navigation

click-outside

A tiny, framework-agnostic utility that closes all elements with an .open class when clicking or tapping outside them — just like dropdowns, popovers, and menus do.

✅ Shadow DOM–safe
✅ ESC key support
.co-trigger / ignore selectors
✅ Custom events (will-close-outside / did-close-outside)
✅ Fully typed via JSDoc


📦 Installation

pnpm i @bgunnarsson/click-outside
# or
npm install @bgunnarsson/click-outside
# or
yarn add @bgunnarsson/click-outside

⚙️ Usage

// clickOutside.mjs
import { clickOutside } from 'click-outside-global';

// initialize once at app startup
const dispose = clickOutside({
  openSelector: '.open',        // elements that should close
  triggerSelector: '.co-trigger', // ignore trigger clicks
  escape: true,                 // also close on Escape
});

// later, if you want to stop listening:
dispose();

Example HTML

<button class="co-trigger">Toggle menu</button>

<div class="dropdown open">
  <p>Dropdown content</p>
</div>

When you click anywhere outside .dropdown and not inside .co-trigger,
the .open class will be removed from all elements with .open.


🧠 Custom Events

Each open element emits two events when closing:

Event Cancelable Description
will-close-outside ✅ Yes Fired before removal. Call event.preventDefault() to cancel.
did-close-outside ❌ No Fired after .open was removed.

Example

document.addEventListener('will-close-outside', (e) => {
  const el = e.target;
  console.log('About to close:', el);

  // Cancel close for sticky elements
  if (el.matches('[data-sticky]')) e.preventDefault();
});

document.addEventListener('did-close-outside', (e) => {
  const el = e.target;
  console.log('Closed:', el);
});

🧩 Options

Option Type Default Description
openSelector string '.open' Selector for open elements.
triggerSelector string Selector for elements that should not close when clicked (e.g. .co-trigger).
ignore (Element | string | (node: Node) => boolean)[] [] Additional elements, selectors, or predicates to ignore.
event 'pointerdown' | 'mousedown' | 'click' 'pointerdown' DOM event to listen for.
escape boolean true Close on Escape key.
capture boolean true Use capture phase (recommended).
root Document | DocumentFragment document Scope for querying open elements.

🧪 License

MIT © 2025 B. Gunnarsson

About

0 dependency click outside handler.

Resources

Stars

Watchers

Forks