Skip to content

JavaScript Tutorial Practical Projects

Project 5: A Modal Dialog

Lesson 244 of 258 2 min read By Deepak Paswan Updated Oct 4, 2026

A modal asks the user for something and blocks the rest of the page. We will use the native <dialog> element so focus, Escape and the backdrop are handled by the browser (Dialog and Modal Basics).

index.html
HTML
<style>
  body { font-family: system-ui, sans-serif; }
  button { font: inherit; padding: 8px 14px; cursor: pointer; border-radius: 6px; border: 2px solid #1a5276; background: #fff; }
  button.primary { background: #1a5276; color: #fff; }
  button:focus-visible { outline: 3px solid #d94a00; outline-offset: 2px; }
  dialog { border: 0; border-radius: 12px; padding: 20px; width: min(320px, 90vw); box-shadow: 0 10px 30px rgba(0,0,0,.3); }
  dialog::backdrop { background: rgba(0, 0, 0, .5); }
  dialog h2 { margin-top: 0; }
  .actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 16px; }
  label { display: block; margin: 8px 0 4px; }
  input { width: 100%; box-sizing: border-box; padding: 8px; font: inherit; }
</style>

<button id="open" class="primary">Subscribe</button>
<p id="result" role="status"></p>

<dialog id="dialog" aria-labelledby="title">
  <form method="dialog" id="form">
    <h2 id="title">Join the newsletter</h2>
    <label for="email">Email</label>
    <input id="email" name="email" type="email" required autocomplete="email">
    <div class="actions">
      <button value="cancel" formnovalidate>Cancel</button>
      <button value="subscribe" class="primary">Subscribe</button>
    </div>
  </form>
</dialog>

<script>
  const dialog = document.querySelector("#dialog");
  const opener = document.querySelector("#open");
  const result = document.querySelector("#result");

  opener.addEventListener("click", () => {
    dialog.showModal();
  });

  dialog.addEventListener("close", () => {
    if (dialog.returnValue === "subscribe") {
      const email = document.querySelector("#email").value;
      result.textContent = `Thanks! We will write to ${email}.`;
    } else {
      result.textContent = "Cancelled.";
    }
    document.querySelector("#form").reset();
  });

  // clicking the dimmed backdrop closes the dialog
  dialog.addEventListener("click", event => {
    if (event.target === dialog) dialog.close("cancel");
  });
</script>

What the browser does for you

  • showModal() puts the dialog above the page, makes the rest inert, moves focus inside and keeps Tab in the dialog.
  • Escape closes it.
  • On close, focus returns to the button that opened it.
  • <form method="dialog"> closes the dialog on submit, and dialog.returnValue holds the value of the pressed button. The required email is validated by the browser before the form closes.

What the script does

  • Opens the dialog on click.
  • Reads the return value in the close event to decide what happened.
  • Resets the form so old text is not shown next time.
  • Closes on a click on the backdrop (event.target === dialog).

Try changing it

  1. Add a Delete confirmation dialog: “Delete this item?” with Cancel as the default (autofocus).
  2. Make the dialog open when the URL has #subscribe.
  3. Add an error message inside the dialog for invalid emails (Custom Validation).
  4. Style the opening animation using the @starting-style rule and transition (check browser support).
dangerous
Use modals sparingly
Interrupting users is expensive. Use them for decisions that must be made before continuing, and make sure there is always a visible way out.