So, I’m trying to make a modal in React. I separated the modal into another file from the element that triggers and renders it to reveal itself. The modal opens but for some reason when I try to get it to close by pressing on the backdrop of the modal, it doesn’t close.
Card.js File:
import React, { useState } from "react";
import "./styles/card.css";
import { Modal } from "./modals";
export const Card = () => {
const [modalState, setModalState] = useState(false);
const openModal = () => setModalState(true);
const closeModal = () => setModalState(false);
return (
<div className="card" onClick={openModal}>
<p>Hello</p>
{modalState && <Modal closeModal={closeModal} />}
</div>
);
};
Modal.js File:
import React from "react";
import "./styles/modal.css";
import { createPortal } from "react-dom";
export const Modal = ({ closeModal }) => {
const stopPropagation = (event) => {
event.stopPropagation();
};
return (
<>
{createPortal(
<div className="modal-backdrop" onClick={closeModal}>
<div className="modal" onClick={stopPropagation}>
<p className="gbye">Goodbye</p>
</div>
</div>,
document.body
)}
</>
);
};
card.css
.card {
background-color: blue;
height: 200px;
width: 200px;
}
modal.css
.modal-backdrop {
position: fixed;
transform: translate(-50% -50%);
height: 100%;
width: 100%;
background-color: rgba(0, 0, 0, 0.8);
top: 0;
bottom: 0;
right: 0;
left: 0;
z-index: 1000;
}
.modal {
position: absolute;
top: 50%;
left: 50%;
background-color: white;
transform: translate(50% 50%);
padding: 20px;
border-radius: 5px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
I tried using createportal to separate it from the root file because I thought, possibly the styles were interfering with each other but that wasn’t the case.
2
Answers
No matter where the portal renders the Modal in the real DOM, in the React Virtual DOM, your Modal is nested under the Card so the click event is bubbled to the card onClick which is
openModal
. That’s why it cannot be closed.Try to move the
Modal
out ofCard
Or stop propagation on the modal backdrop click
Have a nice day!
The issue is that your Modal component is nested in your Card which also has an
onClick
.When you click on the backdrop of your
Modal
the click event is propagated up to the parentCard
component, triggering theonClick
of the card again.Solution
I’ve just reused the
stopPropagation
and created ahandleClose
function that will stop the propagation and action thecloseModal
.Modal.js
Stackblitz with showcasing the event bubbling to the card and triggering the
openModal
– Example