Home > OS >  preventDefault does not work with modal window
preventDefault does not work with modal window

Time:11-21

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.

  • Related