Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

click anywhere to close dropdown in react

I have multiple custom build dropdown component of react on a page. I trigger the list item to open using setState

toggleDropdown = (id) => {
        this.setState(prevState => ({
            [`dropdown${name}`]: !prevState[`dropdown${id}`] //dropdownA, dropdownB, dropdownC and so on
        }))
    }

this will also toggle it if the dropdown was clicked when the menu is open. But then I have few more dropdowns, other dropdown won't close if I open a dropdown, how to solve this? I do a "hacky" way mixing react with jquery in componentWillMount, binding click event on body, check if the dropdown item is visible, if yes close it.

My question is, is there any better practice to avoid using jquery?

like image 473
Alan Jenshen Avatar asked Jun 17 '17 09:06

Alan Jenshen


People also ask

How do I close a drop down on click outside?

Answer: Use the jQuery on() method You can use the jQuery click() method in combination with the on() method to hide the dropdown menu when the user click outside of the trigger element.

How do you hide dropdown menu on click outside of the element in React?

Here we go: abandon stop propagation, go back to listening to the document object, and use the node. contains API to determine whether a click event happens outside the dropdown menu. If it does, hide the dropdown menu, since we need to use ref to save the DOM node in React in order to use the API.

How do I hide a drop down in React?

You can hide the dropdown arrow from the DropDownButton by adding class e-caret-hide to DropDownButton element using cssClass property.


2 Answers

My suggestion is that you use the synthetic events onFocus and onBlur to trigger open/close state. onFocus will trigger when the element is clicked and onBlur will trigger when "unfocusing" (clicking outside). See docs.

Also tabIndex attribute/prop is needed for focus/blur to work on non input type elements.

I can recommend looking at the source of react-select and how they handle focusing/bluring.

Here is an example, you can see a demo of it here

import React from "react";

class Dropdown extends React.Component {
  state = {
    open: false
  };

  toggleDropdown() {
    this.setState({ open: !this.state.open });
  }

  render() {
    return (
      <div
        style={{ border: "1px solid #CCC" }}
        onBlur={() => this.toggleDropdown()}
        onFocus={() => this.toggleDropdown()}
        tabIndex="0"
      >
        Dropdown
        {this.state.open && (
          <div>
            <div>Red</div>
            <div>Green</div>
            <div>Blue</div>
          </div>
        )}
      </div>
    );
  }
}

export default Dropdown;
like image 99
heyhugo Avatar answered Oct 03 '22 22:10

heyhugo


You could use the react-onclickoutside library that abstracts the body event handling for you. You just have to wrap your component in their onClickOutside higher order component that will execute the handleClickOutside callback any time the click happens outside of the drop down. That way you can have a private "open" state in all dropdowns and don't care about how the handling is achieved.

The code might look like that:

import React, { Component } from 'react'
import onClickOutside from 'react-onclickoutside'

class Dropdown extends Component {
    constructor() {
        this.state = {open: false}
    }

    // Method automatically executed by the library.
    handleClickOutside() {
        this.setState({open: false})
    }

    render() { ... }
}

export default onClickOutside(Dropdown)
like image 27
Mateusz Kocz Avatar answered Oct 03 '22 23:10

Mateusz Kocz