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

Use redux-like middleware for useReducer in React

If you have used Redux before, you would be aware of the concept of middlewares. Now that useReducer has become a commonly...

How to write your own custom React hooks

If you have been using react for a while, chances are you have come across the need to extract some logic into...

Palindromic Substrings: Demystifying Programming Interview

This is the second post in the Demystifying Programming Interview series, which aims at helping students and professionals who are planning to...

Converting a business problem to a machine learning problem

Businesses these days are generating and consuming a huge amount of data. This data varies in variety, volume, velocity, and veracity (4Vs...

How to develop your curiosity for a better self?

Curiosity is the reason why most of the breakthrough discoveries and remarkable inventions have happened throughout history. In the absence of curiosity,...

Related Stories

Leave A Reply

Please enter your comment!
Please enter your name here

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.