Start · Sprachen · JavaScript · Referenz · HTMLDialogElement: cancel

HTMLDialogElement: cancel

Ereignis

Wird an einem <code>&lt;dialog&gt;</code> ausgelöst, wenn der Benutzer das Schließen anfordert, z. B. mit Esc. Mit <code>preventDefault()</code> lässt sich das Schließen verhindern.

seit JavaScript Baseline: alle modernen Browser (seit 2022) Kategorie: webapi

Signatur

dialog.addEventListener("cancel", handler)

Beschreibung

Das cancel-Ereignis wird an einem HTMLDialogElement ausgelöst, wenn der Benutzer eine Schließanforderung (englisch „close request“) stellt. Typische Auslöser sind die Esc-Taste bei einem modal geöffneten Dialog (showModal()), die Zurück-Geste bzw. die Zurück-Taste auf Android und der Aufruf von dialog.requestClose(). Ein Aufruf von dialog.close() löst dagegen kein cancel aus, sondern nur close.

Das Ereignis ist ein einfaches Event. Es lässt sich abbrechen (cancelable: true), steigt aber nicht in der DOM-Hierarchie auf (bubbles: false). Ruft man im Handler event.preventDefault() auf, bleibt der Dialog offen. Das eignet sich gut für Rückfragen wie „Ungespeicherte Änderungen verwerfen?“. Wird das Ereignis nicht abgebrochen, schließt der Browser den Dialog und löst anschließend close aus.

Einen Handler registriert man entweder mit addEventListener("cancel", …) oder über die Eigenschaft dialog.oncancel. Über die Eigenschaft ist immer nur ein Handler möglich. Mit addEventListener kann man mehrere Handler registrieren und sie mit removeEventListener gezielt wieder entfernen.

Parameter

Name Typ Default Beschreibung
$type Pflicht string Der Ereignisname, hier immer "cancel".
$handler Pflicht (event: Event) => void | EventListener Funktion, die bei der Schließanforderung aufgerufen wird. Sie erhält ein Event mit cancelable === true.
$options boolean | AddEventListenerOptions false Optionen wie once, signal (zum Entfernen über einen AbortController) oder capture.

Beispiele

Schließen bei ungespeicherten Änderungen verhindern

const dialog = document.querySelector('#editor-dialog');
const form = dialog.querySelector('form');
let dirty = false;

form.addEventListener('input', () => { dirty = true; });

dialog.addEventListener('cancel', (event) => {
  if (dirty && !confirm('Ungespeicherte Änderungen verwerfen?')) {
    event.preventDefault(); // Dialog bleibt offen
    return;
  }
  console.log('Dialog per Esc geschlossen');
});

dialog.showModal();
Dialog per Esc geschlossen

Handler über die Eigenschaft oncancel setzen

const dialog = document.querySelector('dialog');

dialog.oncancel = (event) => {
  console.log('cancel ausgelöst, abbrechbar:', event.cancelable);
};

dialog.onclose = () => {
  console.log('returnValue:', JSON.stringify(dialog.returnValue));
};

dialog.showModal();
// Benutzer drückt Esc
cancel ausgelöst, abbrechbar: true returnValue: ""

Listener mit removeEventListener bzw. AbortSignal entfernen

const dialog = document.querySelector('#wizard');

const blockCancel = (event) => {
  event.preventDefault();
  console.log('Bitte den Assistenten erst abschließen.');
};

dialog.addEventListener('cancel', blockCancel);
dialog.showModal();

// Nach dem letzten Schritt darf Esc den Dialog wieder schließen
document.querySelector('#finish').addEventListener('click', () => {
  dialog.removeEventListener('cancel', blockCancel);
});

// Alternative: mehrere Listener auf einmal über ein Signal entfernen
const controller = new AbortController();
dialog.addEventListener('cancel', () => console.log('cancel'), { signal: controller.signal });
controller.abort();
Bitte den Assistenten erst abschließen.

Schließanforderung aus eigenem Code: requestClose()

const dialog = document.querySelector('dialog');

dialog.addEventListener('cancel', () => console.log('cancel'));
dialog.addEventListener('close', () => console.log('close'));

dialog.showModal();

// Verhält sich wie Esc: zuerst cancel (abbrechbar), dann close
if (typeof dialog.requestClose === 'function') {
  dialog.requestClose('abgebrochen');
} else {
  dialog.close('abgebrochen'); // löst nur close aus
}
cancel close

// Wichtig · Fallstricke

  • Kein Bubbling: cancel steigt nicht auf. Ein Listener auf document erreicht das Ereignis daher nur mit { capture: true }.
  • Nicht beliebig blockierbar: Um Missbrauch zu verhindern, beachten Chromium-Browser preventDefault() nur, wenn der Benutzer seit der letzten Schließanforderung mit der Seite interagiert hat. Drückt er zweimal hintereinander Esc, schließt der Dialog trotzdem, ohne dass cancel noch einmal ausgelöst wird. Verlassen Sie sich also nicht darauf, dass sich ein Dialog dauerhaft offen halten lässt.
  • close() ist kein cancel: dialog.close() und ein <form method=\"dialog\">-Absenden lösen nur close aus. Nur Schließanforderungen und requestClose() lösen cancel aus.
  • Nicht modale Dialoge: Ein mit show() geöffneter Dialog reagiert standardmäßig nicht auf Esc, daher tritt dort in der Regel kein cancel auf. Das neuere Attribut closedby ändert dieses Verhalten, wird aber noch nicht überall unterstützt.
  • Kompatibilität: Das Ereignis selbst wird in allen modernen Browsern unterstützt (Safari ab 15.4). requestClose() und closedby sind neu (Chrome 134+, Firefox 139+). Prüfen Sie vor der Nutzung, ob sie verfügbar sind.
  • Gleicher Name, anderes Element: Auch <input type=\"file\"> kennt ein cancel-Ereignis. Dort wird es ausgelöst, wenn der Dateiauswahldialog ohne Auswahl geschlossen wird.