<dialog>, showModal() & returnValue

Confirm with a dialog

Lesson 17 of 20 · 12 min · Module 5: Smoother interactions

Deleting something by accident is painful. The built-in dialog element gives you an accessible confirmation box: it keeps focus inside, closes with Escape, and tells you which button was chosen.

Start this lesson →

Free. No installation: you write and run the code in your browser, and it is checked automatically.

By the end, you’ll be able to…

  • Open a modal dialog with showModal()
  • Read the chosen button from returnValue
  • Look after focus when the opening button disappears

The idea

dialog.showModal() opens a dialog above the page and makes everything behind it inert. A form inside it with method="dialog" closes the dialog when one of its buttons is pressed, and that button’s value becomes dialog.returnValue. Listen for the dialog’s close event to act on the choice.

<dialog id="leave">
  <form method="dialog">
    <p>Leave without saving?</p>
    <button value="stay">Stay</button>
    <button value="leave">Leave</button>
  </form>
</dialog>
<script>
  const dialog = document.querySelector('#leave');
  dialog.addEventListener('close', () => console.log(dialog.returnValue));
  dialog.showModal();
</script>

01Accessibility built in

A modal dialog moves focus inside, keeps Tab within it, closes with Escape, and hides the rest of the page from screen readers. Building the same from div elements takes many lines and is easy to get wrong.

02returnValue remembers

Closing with a button sets returnValue to that button’s value, but closing with Escape leaves it unchanged. Without a reset, the answer to the previous dialog is read again, which here would delete a project nobody confirmed.

dialog.returnValue = ''; // forget the last answer
dialog.showModal();

03Make the safe choice easy

autofocus on Cancel means a quick Enter cannot destroy anything. Name the action on the button (Delete, not OK) and say in the dialog what will be lost.

Your turn

1) In one click listener on #projects, react to the .delete buttons: remember the project’s <li>, put its name in #confirm-name, set dialog.returnValue to '', and open the dialog with showModal(). 2) In the dialog’s close listener, only when returnValue is delete: remove the project, write Deleted and its name in #status, such as Deleted Recipe box, and move focus to the #title heading, because the button that opened the dialog no longer exists.

What the checks look for

  • Delete opens the dialog for that project
  • Cancel keeps every project
  • Confirming deletes the right project
  • Focus moves to the heading after a deletion
  • Closing with Escape after a deletion keeps the project
  • Projects can be deleted one after another
Try it in the editor →

Take this with you

Reset returnValue, call showModal(), and act only on the button that was chosen.

Go a little further

Add an Undo button next to the status message that puts the last deleted project back in its old place.

Learn JavaScript in the Browser for free

20 short lessons with real code and instant checks.

See the whole course →