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
pnpm i @bgunnarsson/click-outside
# or
npm install @bgunnarsson/click-outside
# or
yarn add @bgunnarsson/click-outside// 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();<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.
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. |
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);
});| 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. |
MIT © 2025 B. Gunnarsson