react-safe-click-outside
v0.0.1
Published
A modern, StrictMode-safe React library for detecting clicks outside elements
Maintainers
Readme
react-safe-click-outside
A modern, StrictMode-safe React library for detecting clicks outside elements. Provides both a React hook (useClickOutside) and a Higher-Order Component (withClickOutside) for maximum flexibility.
Features
- ✅ React 18+ compatible with full StrictMode support
- ✅ TypeScript native with full type definitions
- ✅ Zero dependencies (except React peer dependency)
- ✅ Tiny bundle size - ~600 bytes gzipped, tree-shakeable
- ✅ No
findDOMNode- uses modern React patterns - ✅ Both hook and HOC - works with functional and class components
- ✅ Touch-friendly - handles both mouse and touch events
Installation
npm install react-safe-click-outsideor
yarn add react-safe-click-outsideor
pnpm add react-safe-click-outsideUsage
Using the Hook (Recommended)
Perfect for functional components:
import { useRef } from 'react';
import { useClickOutside } from 'react-safe-click-outside';
function Dropdown() {
const dropdownRef = useRef<HTMLDivElement>(null);
useClickOutside(dropdownRef, () => {
console.log('Clicked outside dropdown!');
// Close dropdown, hide modal, etc.
});
return (
<div ref={dropdownRef}>
<h3>Dropdown Menu</h3>
<ul>
<li>Option 1</li>
<li>Option 2</li>
<li>Option 3</li>
</ul>
</div>
);
}Complete Example with State
import { useRef, useState } from 'react';
import { useClickOutside } from 'react-safe-click-outside';
function Modal() {
const [isOpen, setIsOpen] = useState(false);
const modalRef = useRef<HTMLDivElement>(null);
useClickOutside(modalRef, () => {
if (isOpen) {
setIsOpen(false);
}
});
return (
<div>
<button onClick={() => setIsOpen(true)}>Open Modal</button>
{isOpen && (
<div
style={{
position: 'fixed',
top: 0,
left: 0,
right: 0,
bottom: 0,
background: 'rgba(0,0,0,0.5)',
}}
>
<div
ref={modalRef}
style={{
background: 'white',
padding: '2rem',
margin: '100px auto',
maxWidth: '500px',
}}
>
<h2>Modal Content</h2>
<p>Click outside to close!</p>
</div>
</div>
)}
</div>
);
}Using the HOC
Perfect for class components or legacy React code:
import React, { Component } from 'react';
import {
withClickOutside,
WithClickOutsideProps,
} from 'react-safe-click-outside';
interface Props extends WithClickOutsideProps {
title: string;
}
class Popover extends Component<Props> {
handleClickOutside = () => {
console.log('Clicked outside popover!');
// Handle outside click
};
render() {
return (
<div>
<h3>{this.props.title}</h3>
<p>Popover content</p>
</div>
);
}
}
// Wrap the component
export default withClickOutside(Popover);
// Usage:
// <Popover title="My Popover" onClickOutside={handleClose} />HOC with Functional Component
import {
withClickOutside,
WithClickOutsideProps,
} from 'react-safe-click-outside';
interface Props extends WithClickOutsideProps {
message: string;
}
const Tooltip: React.FC<Props> = ({ message }) => {
return <div className='tooltip'>{message}</div>;
};
export default withClickOutside(Tooltip);API Reference
useClickOutside(ref, handler)
A React hook that triggers a callback when clicking outside a referenced element.
Parameters:
ref: RefObject<HTMLElement>- A React ref object pointing to the element to monitorhandler: (event: MouseEvent | TouchEvent) => void- Callback function executed when clicking outside
Returns: void
Example:
const ref = useRef<HTMLDivElement>(null);
useClickOutside(ref, (event) => {
console.log('Clicked outside!', event);
});withClickOutside(Component)
A Higher-Order Component that adds click-outside detection to any component.
Parameters:
Component: ComponentType<P>- The component to wrap
Returns: ComponentType<P & WithClickOutsideProps>
Injected Props:
onClickOutside?: (event: MouseEvent | TouchEvent) => void- Callback for outside clicks
Example:
const EnhancedComponent = withClickOutside(MyComponent);
<EnhancedComponent onClickOutside={() => console.log('Outside click!')} />;TypeScript Support
This library is written in TypeScript and includes full type definitions. No need to install @types/* packages.
import {
useClickOutside,
withClickOutside,
WithClickOutsideProps,
} from 'react-safe-click-outside';Browser Support
Works in all modern browsers that support:
- ES6+
- React 17+
- Standard DOM events (mousedown, touchstart)
How It Works
The library listens for mousedown and touchstart events on the document. When an event occurs, it checks if the click target is outside the referenced element. If so, it triggers the provided callback.
Key Implementation Details:
- Uses modern React patterns (no
findDOMNode) - StrictMode-safe
- Properly cleans up event listeners on unmount
- Uses
display: contentsin HOC to avoid wrapper div affecting layout - Handles both mouse and touch events
Best Practices
- Memoize your handler to avoid unnecessary re-renders:
const handleClickOutside = useCallback(() => {
setIsOpen(false);
}, []);
useClickOutside(ref, handleClickOutside);- Conditional logic should be inside the handler:
useClickOutside(ref, () => {
if (isOpen) {
setIsOpen(false);
}
});- Multiple refs: If you need to ignore clicks on multiple elements, use a wrapper:
<div ref={wrapperRef}>
<button>Trigger</button>
<div>Content</div>
</div>Common Use Cases
- Dropdown menus
- Modals and dialogs
- Popovers and tooltips
- Context menus
- Date pickers
- Autocomplete suggestions
- Mobile navigation menus
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
MIT
Credits
Built with ❤️ for the React community
