We are offering a menu here. In case the menu is visible, users should be able to close it by clicking anywhere on the screen:
class Menu extends Component {
componentWillMount() {
document.addEventListener("click", this.handleClickOutside);
}
componentWillUnmount() {
document.removeEventListener("click", this.handleClickOutside);
}
openModal = () => {
this.props.showModal();
};
handleClickOutside = ({ target }) => {
const { displayMenu, toggleMenu, displayModal } = this.props;
if (displayMenu) {
if (displayModal || this.node.contains(target)) {
return;
}
toggleMenu();
}
};
render() {
return (
<section ref={node => (this.node = node)}>
<p>
<button onClick={this.openModal}>open modal</button>
</p>
<p>
<button onClick={this.openModal}>open modal</button>
</p>
<p>
<button onClick={this.openModal}>open modal</button>
</p>
</section>
);
}
}
In the menu, users have the option to open a modal by clicking on a button within the menu. To close the modal, there are two options: click on the "close modal" button inside the modal itself, or click on the backdrop/overlay outside the modal:
class Modal extends Component {
hideModal = () => {
this.props.hideModal();
};
onOverlayClick = ({ target, currentTarget }) => {
if (target === currentTarget) {
this.hideModal();
}
};
render() {
return (
<div className="modal-container" onClick={this.onOverlayClick}>
<div className="modal">
<button onClick={this.hideModal}>close modal</button>
</div>
</div>
);
}
}
When both the menu and modal are open, I want the modal to close only when the user clicks on the close modal button or modal overlay. The menu should remain open until the second click (when the modal is already closed). This condition should handle that scenario:
if (displayModal || this.node.contains(target)) {
return;
}
If the displayModal is true
, then nothing should happen. However, in my case, the hideModal
function executes faster than toggleMenu
, which causes issues as displayModal will already be set to false
when handleClickOutside
is called.
For a complete test case with an open menu and modal from the start, please visit: