React useClickOutside and useClickInside hooks
Handling click events in React is usually as simple as adding an onClick
handler to a component. However, there are cases where you need to handle clicks outside or inside a component. This takes some extra effort and, most often than not, requires the use of custom hooks.
useClickOutside
hook
In order to handle clicks outside of a component, you'll first need to have a reference to the component. This is where the useRef()
hook comes in handy. You can then use the useEffect()
hook to add an event listener to the document
and check if the click event occurred outside the component.
const useClickOutside = (ref, callback) => { const handleClick = e => { if (ref.current && !ref.current.contains(e.target)) { callback(); } }; React.useEffect(() => { document.addEventListener('click', handleClick); return () => { document.removeEventListener('click', handleClick); }; }); };
Using the hook is fairly simple. You just need to pass a ref
and a callback
function to handle the click event. The callback
function will be called when the click event occurs outside the component.
const ClickBox = ({ onClickOutside }) => { const clickRef = React.useRef(); useClickOutside(clickRef, onClickOutside); return ( <div className="click-box" ref={clickRef} style={{ border: '2px dashed orangered', height: 200, width: 400, display: 'flex', justifyContent: 'center', alignItems: 'center' }} > <p>Click out of this element</p> </div> ); }; ReactDOM.createRoot(document.getElementById('root')).render( <ClickBox onClickOutside={() => alert('click outside')} /> );
useClickInside
hook
Similarly, you can create a hook to handle clicks inside a component. The logic is almost the same, but you need to check if the click event occurred inside the component. This hook can come in handy when you need to handle clicks on multiple children and you don't want to add an onClick
handler to each of them.
const useClickInside = (ref, callback) => { const handleClick = e => { if (ref.current && ref.current.contains(e.target)) { callback(); } }; React.useEffect(() => { document.addEventListener('click', handleClick); return () => { document.removeEventListener('click', handleClick); }; }); };
Again, you will need to pass the ref
and a callback
function to handle the click event inside the component, same as before.
const ClickBox = ({ onClickInside }) => { const clickRef = React.useRef(); useClickInside(clickRef, onClickInside); return ( <div className="click-box" ref={clickRef} style={{ border: '2px dashed orangered', height: 200, width: 400, display: 'flex', justifyContent: 'center', alignItems: 'center' }} > <p>Click inside this element</p> </div> ); }; ReactDOM.createRoot(document.getElementById('root')).render( <ClickBox onClickInside={() => alert('click inside')} /> );