Skip to content

Instantly share code, notes, and snippets.

@franciscofsales
Created December 11, 2019 14:06
Show Gist options
  • Save franciscofsales/e450906216a7baa4a7357b5f0f60bf24 to your computer and use it in GitHub Desktop.
Save franciscofsales/e450906216a7baa4a7357b5f0f60bf24 to your computer and use it in GitHub Desktop.
Custom hook to trigger callback when there is a click outside the passed in elements or its children
import { useEffect } from 'react';
/**
* Hook that handles clicks outside of the passed refs or its children
*/
export default function useClickOutside(refs: Array<any>, callback: any) {
/**
* Handle click on outside of element
*/
function handleClickOutside(event: { target: any }) {
let clickedOutside = true;
const inspectElement = (elem: any): boolean | null => {
if (elem && elem.current && elem.current.contains(event.target)) {
clickedOutside = false;
return false;
}
if (
elem &&
elem.current &&
elem.current.children &&
elem.current.children.length
) {
for (let j = 0; j < elem.current.children.length; j += 1) {
inspectElement(elem.current.children.item(j));
}
} else {
return true;
}
return null;
};
refs.forEach(ref => {
inspectElement(ref);
});
if (clickedOutside && callback) {
callback();
}
}
useEffect(() => {
// Bind the event listener
document.addEventListener('mousedown', handleClickOutside);
return () => {
// Unbind the event listener on clean up
document.removeEventListener('mousedown', handleClickOutside);
};
});
}
@franciscofsales
Copy link
Author

refs is an array of react refs for the elements that should not trigger events

example usage:

const [isOpen, setIsOpen] = useState(false);
const wrapperRef = useRef(null);
useClickOutside([wrapperRef], () => setIsOpen(false));

<Container ref={wrapperRef}>
  <h1>Title</h1>
</Container>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment