useOnClickOutside
Detect clicks outside of elements. Perfect for closing dropdowns, popups, and modals.
Live Demo
📊 Click Statistics
0 clicks detected
Click anywhere in the gray area
📝 Event Log
No events yet. Try opening the menus!
💡 Try This:
- Open a menu and click outside to close it
- Click inside the menu - it stays open
- Open both menus and close them independently
Code Examples
Basic Dropdown
import { useOnClickOutside } from "@uiblock/hooks";
import { useState, useRef } from "react";
function Dropdown() {
const [isOpen, setIsOpen] = useState(false);
const dropdownRef = useRef(null);
useOnClickOutside(dropdownRef, () => setIsOpen(false));
return (
<div ref={dropdownRef}>
<button onClick={() => setIsOpen(!isOpen)}>
Toggle Dropdown
</button>
{isOpen && (
<div className="dropdown-menu">
<div>Option 1</div>
<div>Option 2</div>
<div>Option 3</div>
</div>
)}
</div>
);
}Multiple Elements
import { useOnClickOutside } from "@uiblock/hooks";
import { useRef } from "react";
function Component() {
const buttonRef = useRef(null);
const menuRef = useRef(null);
// Close when clicking outside both elements
useOnClickOutside([buttonRef, menuRef], () => {
console.log('Clicked outside!');
});
return (
<>
<button ref={buttonRef}>Button</button>
<div ref={menuRef}>Menu</div>
</>
);
}With Options
import { useOnClickOutside } from "@uiblock/hooks";
function Modal({ isOpen, onClose }) {
const modalRef = useRef(null);
useOnClickOutside(modalRef, onClose, {
enabled: isOpen,
eventTypes: ['mousedown', 'touchstart']
});
return isOpen ? <div ref={modalRef}>Modal</div> : null;
}How It Works
Here's the implementation:
import { useEffect, useRef } from 'react'
export function useOnClickOutside(ref, handler, options = {}) {
const { enabled = true, eventTypes = ['mousedown', 'touchstart'] } = options
const savedHandler = useRef(handler)
useEffect(() => {
savedHandler.current = handler
}, [handler])
useEffect(() => {
if (!enabled) return
const listener = (event) => {
const refs = Array.isArray(ref) ? ref : [ref]
// Check if click is inside any of the refs
const isInside = refs.some(r => {
const element = r.current
if (!element) return false
const target = event.target
return element.contains(target)
})
if (!isInside) {
savedHandler.current(event)
}
}
// Add listeners for all event types
eventTypes.forEach(eventType => {
document.addEventListener(eventType, listener)
})
return () => {
eventTypes.forEach(eventType => {
document.removeEventListener(eventType, listener)
})
}
}, [ref, enabled, eventTypes])
}Key Features:
- Supports single or multiple refs
- Configurable event types (mouse and touch)
- Stable handler reference with useRef
- Automatic cleanup on unmount
API Reference
Parameters
ref: RefObject | RefObject[]Element ref(s) to detect outside clicks
handler: (event) => voidCallback when click outside is detected
options?: UseOnClickOutsideOptionsenabled, eventTypes configuration
💡 Use Cases
- Dropdown menus
- Context menus
- Popover components
- Modal dialogs
- Autocomplete suggestions
- Date pickers