Detecting click outside component using React hooks

If you have tried developing your own dropdown, modal, or popover in React, you would have come across this. “How do I detect a click outside my react component so that I can close it?” Detecting click outside component is luckily is not that difficult. This post will use react hooks to implement this functionality.

Before we get started with our process of detecting click outside component using React hooks, there is one hook in particular that we need to know about: useRef.

The useRef hook

- Advertisement -

useRef is a react hook that can be used to access DOM elements. It returns a mutable object whose current property is initialized to the argument that gets passed as an argument.

The syntax for using the hooks looks like this:

const refContainer = useRef(initialValue);

And a sample implementation to focus the component on render would be:

function TextInputWithFocusButton() {
  const inputEl = useRef(null);
  const onButtonClick = () => {
    // `current` points to the mounted text input element
    inputEl.current.focus();
  };
  return (
    <>
      <input ref={inputEl} type="text" />
      <button onClick={onButtonClick}>Focus the input</button>
    </>
  );
}

ref can be used in element tags or components too. It provides a way to access the corresponding DOM nodes. If you pass in a reference object using ref = {}, React sets the current property of the corresponding node. This property is updated whenever the node changes too.

There are other use cases for the useRef hook as well. But this post will be focused only on detecting click outside component.

Setting up event listeners

Now that you know of useRef, we will use it along with an event listener (for mouseDown or click). This listener will be attached to the document whenever the component is rendered. It will also be unmounted whenever the component is hidden. For obtaining this functionality, the useEffect react hook can be used. If you want a deeper insight into the useEffect react hook, you can read the previous post about it.

For the component, there is a showOptionsList variable that is being used as a state variable to determine whether the component is visible or not. Thus, the useEffect will have it as a dependency, and according to its value, the event listener will be added/removed.

 useEffect(() => {
    if (showOptionsList) {
      document.addEventListener('mousedown', handleClickOutside);
    } else {
      document.removeEventListener('mousedown', handleClickOutside);
    }
    return () => {
      document.removeEventListener('mousedown', handleClickOutside);
    };
  }, [showOptionsList]);

Detecting click outside component

Now that the handleClick will be triggered every time a click is registered on the document, all that remains is to check if the click is outside the component or not. For this, a reference to the component is needed. This can be obtained by making use of the useRef hook that was discussed earlier. Thus:

const Select = () => {
  const node = useRef();
  return (
    <div ref={node}>
      // Remaining code
    </div>
  );
};

And then, all that needs to be done in the handle click outside function would be to check if the user clicked outside the component or not. An implementation could be to check the target element of the click and if that equals the reference. But that only works for a single level node. In the case of multiple sub-nodes, the simple comparison would not work.

The .contains() method can be used to solve that problem. It tells if a node is a child of a given node or not. Thus, the implementation of the function becomes:

const handleClickOutside = (e) => {
  if (node.current && node.current.contains(e.target)) {
    // inside click
    return;
  }
  // outside click
  setShowOptionsList(false);
};

The completed source code for the Select implementation can be found on Github if you want to go through it. If you want to make yourself familiar with other react hooks like useState and useEffect, useReducer, or useContext, check out the respective posts.

If there are any other react hooks related things that you would want to cover, or if you have any queries, feel free to drop a comment below.

Recent Articles

Creating a GraphQL API with Apollo Server

One of the many complaints about the GraphQL ecosystem is that there is a lot of indirection around what packages to use...

Natural Language Processing – A 30,000 feet view

Natural Language Processing has gained a lot of popularity owing to an exponential increase in unstructured data generation. Here are some fun...

How to unit-test a private (non-exported) function in JavaScript

When writing unit-tests for JavaScript modules, we often encounter a dilemma wherein the module has some private functions that have not been...

Detecting click outside component using React hooks

If you have tried developing your own dropdown, modal, or popover in React, you would have come across this. "How do I...

Demystifying Programming Interview: Number of Islands

If you are reading this post right now, chances are high that you are not looking for the number of islands in...

Related Stories

Hi there! Want some more knowledge?

Think that the knowledge shared is helpful? You might want to give our mailing list a try. We'll send you 2-4 emails a month, right when new posts come out.

Hi there! Want some more knowledge?

Think that the knowledge shared is helpful? You might want to give our mailing list a try. We'll send you 2-4 emails a month, right when new posts come out.