Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ianobermiller/653cee488fb05a06343cd8a2b5d2b176 to your computer and use it in GitHub Desktop.
Save ianobermiller/653cee488fb05a06343cd8a2b5d2b176 to your computer and use it in GitHub Desktop.
import { useState, useEffect, useRef } from 'react';
// Usage
function App() {
// Create a ref that we add to the element for which we want to detect outside clicks
const ref = useRef();
// State for our modal
const [isModalOpen, setModalOpen] = useState(false);
const openModal = useCallback(() => setModalOpen(true), []);
const closeModal = useCallback(() => setModalOpen(false), []);
// Call hook passing in the ref and a function to call on outside click
useOnClickOutside(ref, closeModal);
return (
<div>
{isModalOpen ? (
<div ref={ref}>
👋 Hey, I'm a modal. Click anywhere outside of me to close.
</div>
) : (
<button onClick={openModal}>Open Modal</button>
)}
</div>
);
}
// Hook
function useOnClickOutside(ref, handler) {
useEffect(() => {
const listener = event => {
// Do nothing if clicking ref's element or descendent elements
if (!ref.current || ref.current.contains(event.target)) {
return;
}
handler(event);
};
document.addEventListener('mousedown', listener);
document.addEventListener('touchstart', listener);
return () => {
document.removeEventListener('mousedown', listener);
document.removeEventListener('touchstart', listener);
};
}, [handler]); // Effect is only run on mount and when handler changes
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment