<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
#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
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.