Reputation: 103
I have a modal reaction component with a button that opens the modal. The modal also has a close button. Here is the code and what the modal looks like:
class Modal extends React.Component {
static defaultProps = {
title: "Modal Title",
float: false,
color: "pink",
children: <div>Add children here!</div>
}
constructor(props) {
super(props)
this.state = {
show: false
}
}
openModal() {
this.setState(
{ show: true }
)
}
closeModal() {
this.setState(
{ show: false }
);
}
render() {
return (
<div>
<button className={"modal-button" + " " + this.props.color} onClick={() => this.openModal()}>{this.props.title}</button>
{this.state.show && <div className={"modal fade-in" + " " + (this.props.float ? "modal-float" : null)}>
<div className="modal-head">
<span>{this.props.title}</span>
<button id='button' onClick={() => this.closeModal()}>x</button>
</div>
<div className="modal-body">
{this.props.children}
</div>
</div>}
</div>
)
}
}
I would like close the modal clicking outside. In another question I saw a code like this
handleClick = event => {
event.preventDefault();
this.setState({ showModal: true }, () => {
document.addEventListener("click", this.closeMenu);
});
};
closeMenu = () => {
this.setState({ menuOpen: false }, () => {
document.removeEventListener('click', this.closeMenu);
});
}
But it also close the modal when I click inside the modal.
Upvotes: 4
Views: 6046
Reputation: 458
You need to add a condition that doesn't close the modal when the modal is open and a click originates inside the modal. To detect where a click is happening, you will probably use refs.
https://reactjs.org/docs/refs-and-the-dom.html
For ex, I added this condition in the closeMenu function:
this.modalRef = React.createRef();
handleClick = event => {
event.preventDefault();
this.setState({ showModal: true }, () => {
document.addEventListener("click", this.closeMenu);
});
};
closeMenu = () => {
if(this.modalRef.current && this.modalRef.current.contains(event.target)) {
return;
}
this.setState({ menuOpen: false }, () => {
document.removeEventListener('click', this.closeMenu);
});
}
render() {
return (
<div ref={this.modalRef}>
// modal component
</div>
);
}
}
This detects 1. if the modal is open (this.modalRef.current
) and 2. if the click originates inside the modal (this.modalRef.current.contains(event.target)
), in which case it returns and does not close the modal.
This explains the approach, although it uses hooks not class components, the concept is the same: https://javascript.plainenglish.io/detect-a-click-outside-of-a-react-component-with-a-reusable-hook-and-useref-a0c282171c3f
Upvotes: 2