demo · v136

Unsaved-changes confirmation

The motivating use case from the Open UI explainer: a real editor dialog whose backdrop click, Esc key and Cancel button all go through the same gate. request-close fires a cancel event we use to detect dirty state and bounce the user into a nested confirmation dialog — no per-trigger glue code.

Probing HTMLDialogElement.prototype.requestClose

Form is clean.

Edit post

Discard unsaved changes?

You have edits that haven't been saved. Are you sure you want to close the editor?

event log

the code

// One handler. ESC, backdrop click, AND the <button command="request-close">
// all fire "cancel" on the dialog before close. We can gate ALL of them with
// one event listener — no per-button onclick wiring.
editor.addEventListener("cancel", (e) => {
  if (formIsDirty(editor.querySelector("form"))) {
    e.preventDefault();           // keep editor open
    confirm.showModal();          // ask "discard?" — sub-dialog handles the real close
  }
});

discardBtn.addEventListener("click", () => {
  confirm.close();
  editor.close();                  // bypasses the cancel gate
});

why this angle

The Open UI explainer for invoker commands and the WHATWG discussion thread call out unsaved-form-confirmation as the motivating reason request-close needed to be its own command (rather than just close). Without it, you'd have to wire the cancel gate three different times: once on the Cancel button, once on backdrop click, once on Esc. With it, the dialog has one cancel entry point and the gate lives in one place. This concept builds the actual editor; the sibling concept shows the raw event mechanics on a toy dialog.

see also