A custom hook that detects clicks outside of a specified element, commonly used for closing modals, dropdowns, and popovers.
src/hooks/use-click-away.ts
function useClickAway(
ref: React.RefObject<HTMLElement | null>,
callback: () => void
): React.RefObject<HTMLElement | null>ref: React ref object pointing to the element to monitorcallback: Function to execute when a click occurs outside the element
- The same ref object passed as parameter (for convenience)
import { useClickAway } from '@/hooks/use-click-away';
import { useRef, useState } from 'react';
function DropdownComponent() {
const [isOpen, setIsOpen] = useState(false);
const dropdownRef = useRef<HTMLDivElement>(null);
// Close dropdown when clicking outside
useClickAway(dropdownRef, () => {
setIsOpen(false);
});
return (
<div>
<button onClick={() => setIsOpen(!isOpen)}>
Toggle Dropdown
</button>
{isOpen && (
<div ref={dropdownRef} className="dropdown-menu">
<p>Dropdown Content</p>
<p>Click outside to close</p>
</div>
)}
</div>
);
}import { useClickAway } from '@/hooks/use-click-away';
import { useToggle } from '@/hooks/use-toggle';
import { useRef } from 'react';
function ModalComponent() {
const [isOpen, { close, toggle }] = useToggle();
const modalRef = useRef<HTMLDivElement>(null);
useClickAway(modalRef, close);
return (
<div>
<button onClick={toggle}>Open Modal</button>
{isOpen && (
<div className="modal-overlay">
<div ref={modalRef} className="modal-content">
<h2>Modal Content</h2>
<p>Click outside to close</p>
</div>
</div>
)}
</div>
);
}- Event delegation: Uses
mousedownevent for reliable detection - Null safety: Safely handles cases where ref.current is null
- Automatic cleanup: Removes event listeners on unmount
- TypeScript support: Fully typed with generic HTMLElement support
- Performance optimized: Only adds listeners when ref is available
- Event type: Uses
mousedowninstead ofclickfor better UX - Event target: Checks if click target is contained within the referenced element
- Cleanup: Properly removes event listeners in useEffect cleanup function
- Dependencies: Includes callback and ref in dependency array
- Dropdown menus: Close when clicking outside
- Modal dialogs: Close modal on backdrop click
- Popover components: Dismiss popovers when clicking elsewhere
- Context menus: Hide context menus on outside click
- Autocomplete: Close suggestions when clicking away
- Date pickers: Close calendar when clicking outside
- Tooltip management: Hide tooltips on outside interaction
- Event:
mousedown(more responsive thanclick) - Target: Uses
event.target as Nodefor type safety - Containment: Uses
element.contains()to check if click is inside - Bubbling: Attaches to
documentto catch all clicks
- Always check if
ref.currentexists before using - Use with state management hooks like
useTogglefor cleaner code - Consider accessibility implications (ESC key handling, focus management)
- Test with keyboard navigation and screen readers
- Should be combined with keyboard event handlers (ESC key)
- Ensure focus management when closing components
- Consider ARIA attributes for better screen reader support
- Modern browsers with full Event API support
- Uses standard DOM methods (
addEventListener,contains) - No special polyfills required