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?
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.
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.
You can hide the dropdown arrow from the DropDownButton by adding class e-caret-hide to DropDownButton element using cssClass property.
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;
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With