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;
}

Links