React On Click Outside HOC
react-onclickoutside is a Higher Order Component (HOC) for React class components, currently at version 6.13.2. It enables wrapped components to detect and respond to click events that occur anywhere in the document outside their own DOM element, commonly used for dismissing menus, modals, or dropdowns. While it supports React versions 15.5.x through 18.x, the library's documentation explicitly recommends against its use with modern React functional components and hooks, suggesting manual implementation of `useRef` and `useEffect` instead. The project indicates it requires community support for continued maintenance. It relies on the `.classList` property, necessitating a polyfill like `dom4` for compatibility with older browsers like Internet Explorer. Releases are irregular, with the last major refactor to ES6 classes occurring in v6.
Common errors
-
Error: Component must implement a handleClickOutside method or pass a handler in the config object.
cause The component wrapped by `onClickOutside` does not define a `handleClickOutside` method as a class member, or a custom handler was not provided in the HOC's configuration.fixEnsure your wrapped class component includes a `handleClickOutside = (event) => { /* ... */ };` method. Alternatively, pass a `handleClickOutside` function as the second argument to `onClickOutside(MyComponent, { handleClickOutside: myCustomHandler })` for more explicit control, especially in TypeScript. -
TypeError: Cannot read property 'classList' of undefined (or null)
cause An element being clicked, or an element in its ancestry, does not have a `classList` property, often due to an older browser (like IE) or attempting to access it on an SVG element in an unsupported environment.fixInstall and include a `classList` polyfill (e.g., `dom4`) in your project to ensure compatibility across all target browsers. For SVG elements in older IE, manual DOM manipulation or ensuring `classList` polyfill covers SVG might be necessary. -
Module not found: Can't resolve 'react-onclickoutside'
cause This usually indicates incorrect import syntax, a missing dependency in `package.json`, or a problem with module resolution in your bundler.fixVerify that `react-onclickoutside` is installed via `npm install react-onclickoutside`. Ensure the import statement is `import onClickOutside from 'react-onclickoutside';` as it is a default export. For CommonJS, use `const onClickOutside = require('react-onclickoutside').default;` -
Trying to use `onClickOutside` with functional components or hooks, but it's not working as expected.
cause The `react-onclickoutside` library is a HOC designed for React class components and does not directly support React hooks or functional components in the same way modern hook-based solutions do.fixFor functional components, implement a custom hook using `useRef` and `useEffect` to detect outside clicks. This involves attaching a ref to your component and an event listener to the document, checking if the clicked target is outside the ref's current element.
Warnings
- deprecated This HOC is not recommended for use with modern React functional components and hooks. The project documentation explicitly advises against installing it if you are using hooks and suggests implementing the logic manually with `useRef` and `useEffect` instead.
- maintenance The project is currently in maintenance mode, and the README indicates it 'needs your support to stay maintained'. This suggests a potential for slower development, bug fixes, or eventual abandonment without community funding.
- gotcha The HOC relies on the `.classList` DOM property. Older browsers, particularly Internet Explorer (pre-Edge) and some older SVG implementations in IE, do not fully support `classList`, which can lead to unexpected behavior or errors.
- breaking Version 6.0.0 refactored the library to use ES6 class syntax, discontinuing the `createClass` and mixin patterns used in older versions (e.g., v4.x, v5.x).
- breaking As of v6.0.0, explicit `passive` settings for touch events are passed, based on the `preventDefault` prop. This can alter the default behavior of touch event handling.
Install
-
npm install react-onclickoutside -
yarn add react-onclickoutside -
pnpm add react-onclickoutside
Imports
- onClickOutside
import { onClickOutside } from 'react-onclickoutside'; const onClickOutside = require('react-onclickoutside');import onClickOutside from 'react-onclickoutside';
- IGNORE_CLASS_NAME
const IGNORE_CLASS_NAME = 'ignore-react-onclickoutside';
import { IGNORE_CLASS_NAME } from 'react-onclickoutside';
Quickstart
import React, { Component } from 'react';
import onClickOutside from 'react-onclickoutside';
class DropdownMenu extends Component {
constructor(props) {
super(props);
this.state = { isOpen: false };
this.toggleMenu = this.toggleMenu.bind(this);
}
toggleMenu() {
this.setState(prevState => ({ isOpen: !prevState.isOpen }));
}
// This method is required by react-onclickoutside HOC
handleClickOutside = (evt) => {
// console.log('Clicked outside!', evt.target);
if (this.state.isOpen) {
this.setState({ isOpen: false });
}
};
render() {
return (
<div style={{ position: 'relative', display: 'inline-block' }}>
<button onClick={this.toggleMenu}>Toggle Dropdown</button>
{this.state.isOpen && (
<div
style={{
position: 'absolute',
backgroundColor: '#f9f9f9',
minWidth: '160px',
boxShadow: '0px 8px 16px 0px rgba(0,0,0,0.2)',
zIndex: 1,
padding: '12px 16px',
marginTop: '5px'
}}
>
<a href="#" style={{ display: 'block', textDecoration: 'none', color: 'black' }}>Link 1</a>
<a href="#" style={{ display: 'block', textDecoration: 'none', color: 'black' }}>Link 2</a>
<a href="#" style={{ display: 'block', textDecoration: 'none', color: 'black' }}>Link 3</a>
</div>
)}
</div>
);
}
}
export default onClickOutside(DropdownMenu);