Modal
Implement a modal window that opens with a button click and can be closed with a close button or by clicking outside the modal.
Solution
Explanation
The HTML Structure
You have a container div and the modal. The modal has a button.
Showing the Modal
The button's onClick
property is hooked up to a turnOnModal
function. This simple function along with turnOffModal
, control the useState
value, showModal
.
The short-circuit evalutation &&
allows the modal to be shown conditionally on whether showModal
is true or false.
Hiding the Modal button
A button is present on the modal with the function turnOffModal
.
Hiding the modal on container click
This requires more thought.
The container has the onClick
property linked to turnOffModal
but there's and issue. With event propagation
if we don't specify that the part of the container that is clicked on, is actually the container, and not the modal, then clicking the modal will also close the modal. This would mean you cannot interact with the modal or any of the contents inside it. Hence the if statement
.
Code
import { useState } from "react";
import styles from "./Solution.module.css";
const Solution = () => {
const [showModal, setShowModal] = useState(false);
const turnOnModal = () => setShowModal(true);
const turnOffModal = () => setShowModal(false);
const handleContainerClick: React.MouseEventHandler<HTMLDivElement> = (
event
) => {
// Check if the click is on the container itself to close the modal
if ((event.target as HTMLDivElement).id === "container") {
turnOffModal();
}
};
return (
<div className={styles.container}>
{showModal && (
<div
id="container"
onClick={handleContainerClick}
className={styles.modalContainer}
role="dialog"
aria-modal="true"
>
<div className={styles.modal}>
<button
onClick={turnOffModal}
aria-label="Click to close"
className={styles.close}
>
X
</button>
<h3>This is a modal</h3>
</div>
</div>
)}
<button
onClick={turnOnModal}
aria-label="Show Modal"
className={styles.open}
>
Show Modal
</button>
</div>
);
};
export default Solution;
Styling
.container {
position: relative;
background-color: #bfe6de;
width: 100%;
height: 500px;
display: grid;
place-content: center;
}
.open {
padding: 5px;
cursor: pointer;
}
.close {
position: absolute;
top: 10px;
right: 10px;
width: 30px;
padding: 5px;
cursor: pointer;
}
.modalContainer {
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
background-color: rgba(0, 0, 0, 0.8);
display: grid;
place-content: center;
}
.modal {
position: relative;
background-color: rgb(224, 224, 224);
width: 200px;
height: 200px;
display: grid;
place-content: center;
}