I'm trying to create a modal window that can be closed by clicking on either ouside the modal window itself or by clicking on a close button
const onCloseHandler = (e) => {
e.stopPropagation();
setIsModalOpen(false);
};
return (
<div className="overlay" onClick={onCloseHandler}>
<div className="modal-window">
<div type="button" className="close-button" onClick={onCloseHandler}>
<CloseIcon />
</div>
<img src={image} alt="task" className="modal-image" />
</div>
</div>
);
The problem is preventDefault
does not work so the modal window closes even if I click on an image or div with modal-window
class.
I tried to use
const onCloseHandler = (e) => {
if (e.target !== e.currentTarget) {
return;
}
setIsModalOpen(false);
};
And it works but it does not seem like a good solution. And also it does not close the modal window when click on a CloseIcon. It is just an svg inside so it's not possible to use pointer-events: none
on it.
CodePudding user response:
You need to stopPropagation
on your modal-window
element.
Remember that clicking is going to start at the most deeply nested element, and then (by default) propagate/bubble up through all higher level elements.
And so of course, in your current solution, of course, given that modal-window
is inside overlay
, clicking anything inside modal-window
also ends up counting as a click on overlay
.
So you could make it so that overlay
is not the parent of modal-window
, à la John Li's answer.
Or, if you retain the existing structure, the click events would be:
`overlay` -> Close the modal
`modal-window` -> stopPropagation, do nothing.
`close-button` -> Close the modal, allow propagation (propagation will stop at `modal-window`)
CodePudding user response:
A cleaner solution might be moving modal-window
out of overlay
.
This way, modal-window
is independent to overlay
. Although it can be styled to be stacking on top of it, because overlay
is not a parent of modal-window
, clicking on modal-window
will not trigger the event on overlay
.
<>
<div className="overlay" onClick="{onCloseHandler}"></div>
<div className="modal-window">
<div type="button" className="close-button" onClick="{onCloseHandler}">
<CloseIcon />
</div>
<img src="{image}" alt="task" className="modal-image" />
</div>
</>
Alternatively, do a condition check on e.target
based on some attributes could also work. This way does not require restructuring of the elements.
const onCloseHandler = (e) => {
if (e.target.className === "modal-window") return;
setIsModalOpen(false);
};
Hope this will help.