How to close the dropdown when clicked outside its division in React.

During my internship. One day I was working on building some dropdown filters for our company's product. Initially, I thought yeah it's not too big a deal. I can simply store one state and render the list on setting the state as true. So initial phase was easy for me. So to begin with let's create a simple dropdown component in React.

import { Component } from "react";
import "./styles.css";

class Dropdown extends Component {
  constructor(props) {
    super(props);
    this.state = {
      showdropdown: false
    };
    this.closeSelector = this.closeSelector.bind(this);
  }


  render() {
    return (
      <div>
        <div id="dropdownselect" class="dropdownselect">
          <div
            class="dropdownToggler"
            onClick={() =>
              this.setState({ showdropdown: !this.state.showdropdown })
            }
          >
            Toggle it
          </div>
          {this.state.showdropdown === true && (
            <div class="dropdownBox">
              <div class="item">Item 1 </div>
              <div class="item"> Item 2</div>
              <div class="item">Item 3</div>
              <div class="item">Item 4</div>
            </div>
          )}
        </div>
      </div>
    );
  }
}

export default App;

Now, this is a basic react component in which if we click on toggler div the item list will be rendered below it and if we again click on toggler it will close. But as we have seen in almost every good UI when we click outside any dropdown it automatically closes all the open dropdowns and that's the best practice too.

So that was a bit of a challenge initially until I found out there is a function that we can use over our HTML document i.e closest() so it works something like if we click over something in UI then it traverses the Element and its parents (heading toward the document root) until it finds a node that matches the provided selector string. So in our case as we can see we need to find out if someone clicked inside our dropdown or not so we check it like

e.target.closest('#dropdownselector')

we can use any selector here id, class, etc. but I am using it because it's unique and will give a more accurate solution. so now we can add an event listener in componentDidMount to check if the place where we are clicking is inside our dropdown div or not if it's not then we can again set the state for showing dropdown as false.

closeSelector(e) {
    let dropdownBoxClicked = e.target.closest("#dropdownselect");
    console.log("ssss", dropdownBoxClicked);
    if (!dropdownBoxClicked) {
      this.setState({ showdropdown: false });
    }
  }

  componentDidMount() {
    window.addEventListener("click", (e) => this.closeSelector(e));
  }

And also it's a good practice always to remove the event listeners when the component is unmounted.

componentWillUnMount() {
    window.removeEventListener("click", (e) => this.closeSelector(e));
  }

Now if we click outside the dropdown our dropdown will automatically close.

dropdown.gif

CodeSandbox Link

More about how element.closest() works

Thanks.