Skip to content

Instantly share code, notes, and snippets.

@meinefinsternis
Forked from elie222/withClickOutside.tsx
Created July 20, 2023 07:06
Show Gist options
  • Save meinefinsternis/00b4f09f70f98afa17c6e4d224117594 to your computer and use it in GitHub Desktop.
Save meinefinsternis/00b4f09f70f98afa17c6e4d224117594 to your computer and use it in GitHub Desktop.
HOC for closing an item when clicked outside. Useful for dropdowns and tooltips
import * as React from 'react'
import hoistNonReactStatic from 'hoist-non-react-statics'
import { findDOMNode } from 'react-dom'
export interface WithClickOutsideProps {
close: () => void
containerElement?: React.RefObject<any>
}
const withClickOutside = <P extends WithClickOutsideProps>(
WrappedComponent: React.ComponentType<P>
) => {
class WithClickOutside extends React.Component<P> {
static displayName: string
public componentDidMount() {
this.addOutsideClickHandler()
}
public componentWillUnmount() {
this.removeOutsideClickHandler()
}
private handleOutsideClick: EventListener = event => {
// potentially bad pattern:
// https://reactjs.org/docs/strict-mode.html#warning-about-deprecated-finddomnode-usage
// probs fine:
// https://github.com/facebook/react/issues/9217#issuecomment-287622539
const node =
(this.props.containerElement && this.props.containerElement.current) || findDOMNode(this)!
if (!node.contains(event.target as Node)) {
this.props.close()
}
}
private addOutsideClickHandler = () => {
if ('ontouchend' in window) {
document.addEventListener('touchend', this.handleOutsideClick)
} else {
document.addEventListener('click', this.handleOutsideClick)
}
}
private removeOutsideClickHandler = () => {
document.removeEventListener('touchend', this.handleOutsideClick)
document.removeEventListener('click', this.handleOutsideClick)
}
render() {
return <WrappedComponent {...this.props} />
}
}
WithClickOutside.displayName = `WithClickOutside(${WrappedComponent.displayName ||
WrappedComponent.name ||
'Component'})`
return hoistNonReactStatic(WithClickOutside, WrappedComponent)
}
export default withClickOutside
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment