<div class="section">
  <h2>Modal Example</h2>
  <button class="button modal-trigger" aria-controls="modal">Open Modal</button>

  <dialog id="modal" class="modal">
    <div class="modal-content">
      <div class="modal-header">
        <h2>Modal Title</h2>
        <button class="modal-dismiss" title="Close modal" data-modal-dismiss>
          &#10005;
          <span class="sr-only">Close modal</span>
        </button>
      </div>
      <div class="modal-body">
        <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Eum, obcaecati ut modi cumque corporis ad asperiores rerum rem aliquam porro vitae quibusdam similique incidunt laborum quia odio, labore perferendis saepe!</p>
      </div>
      <div class="modal-footer">
        <p>This is the modal footer</p>
      </div>
    </div>
  </dialog>
</div>
:root {
  --color-accent: hsla(212, 100%, 45%, 1);
  --color-background: hsla(0, 0%, 95%, 1);
  --color-border: hsl(0, 0%, 90%);
}

.modal {
  --_modal-min-height: 500px;
  --_modal-max-width: min(520px, 100%);
  --_modal-inset: 0;
  --_modal-padding: 1rem;
  --_modal-border-radius: 0.5rem;

  margin: auto;
  padding: 0;
  border: 0;
  background-color: transparent;
  inset: var(--_modal-inset);
  inline-size: 100%;
  max-inline-size: var(--_modal-max-width);
  animation: dialogFadeIn 300ms ease forwards;
}

.modal::backdrop {
  background-color: rgba(0, 0, 0, 0.65);
}

.modal-header,
.modal-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  background-color: var(--color-background);
  padding: var(--_modal-padding);
}

.modal-header {
  border-block-end: 1px solid var(--color-border);
  border-radius: var(--_modal-border-radius) var(--_modal-border-radius) 0 0;
}

.modal-body {
  background-color: var(--color-background);
  padding: var(--_modal-padding);
}

.modal-footer {
  border-block-start: 1px solid var(--color-border);
  border-radius: 0 0 var(--_modal-border-radius) var(--_modal-border-radius);
}

/* 
 * Basic reset and styles
*/

body {
  font-family: sans-serif;
  min-block-size: 100vh;
}

.section {
  display: grid;
  place-content: center;
  block-size: 100vh;
}

.section > h2 {
  margin-block-end: 0.625rem;
}

button {
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 0.325rem;
  color: var(--color-accent);
  background-color: transparent;
  border: 0;
}

.button {
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.5rem 0.625rem;
  border-radius: 8px;
  color: #fff;
  background-color: var(--color-accent);
  border: 1px solid var(--color-accent);
}

.sr-only {
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  height: 1px;
  overflow: hidden;
  position: absolute;
  white-space: nowrap;
  inline-size: 1px;
}
const modalTriggers = document.querySelectorAll(".modal-trigger");

modalTriggers.forEach(handleShow);

function handleShow(trigger) {
  trigger.addEventListener("click", () => {
    const dialogId = trigger.getAttribute("aria-controls");
    const dialog = document.getElementById(dialogId);
    const modalDismiss = dialog.querySelectorAll("[data-modal-dismiss]");
    if (!dialog) return;
    dialog.showModal();

    modalDismiss.forEach((dismiss) => {
      dismiss.addEventListener("click", closeModal);
    });

    dialog.addEventListener("click", closeDialogOnClickOutside);

    function closeModal(e) {
      dialog.close();

      modalDismiss.forEach((dismiss) => {
        dismiss.removeEventListener("click", closeModal);
      });

      dialog.removeEventListener("click", closeDialogOnClickOutside);
      document.removeEventListener("click", closeDialogOnClickOutside);
    }

    function closeDialogOnClickOutside(e) {
      e.target === dialog && closeModal();
    }
  });
}
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.