← Back to all snippets
JAVASCRIPT

Handling Clicks Outside a Component with useOnClickOutside

Implement a `useOnClickOutside` React hook to detect clicks outside a specified element, perfect for closing dropdowns, modals, or context menus.

function useOnClickOutside(ref, handler) {
  React.useEffect(() => {
    const listener = (event) => {
      // Do nothing if clicking ref's element or descendant 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);
    };
  }, [ref, handler]); // Re-run if ref or handler changes
}

// Example usage:
function Dropdown() {
  const [isOpen, setIsOpen] = React.useState(false);
  const dropdownRef = React.useRef();

  useOnClickOutside(dropdownRef, () => setIsOpen(false));

  return (
    React.createElement("div", { ref: dropdownRef, style: { position: 'relative', display: 'inline-block' } },
      React.createElement("button", { onClick: () => setIsOpen(!isOpen) }, "Toggle Dropdown"),
      isOpen && (
        React.createElement("div", {
          style: {
            position: 'absolute', top: '100%', left: 0,
            border: '1px solid #ccc', padding: '10px', background: 'white'
          }
        },
          "Dropdown Content"
        )
      )
    )
  );
}
How it works: The `useOnClickOutside` hook simplifies the common pattern of closing a UI element (like a dropdown or modal) when a user clicks outside of it. It takes a `ref` to the element and a `handler` function. Internally, it attaches `mousedown` and `touchstart` event listeners to the document. When an event occurs, it checks if the click originated from inside the referenced element or its children. If not, it executes the provided `handler`. The `useEffect` hook ensures the listeners are properly attached and cleaned up when the component mounts/unmounts or dependencies change.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs