Signatur
Beschreibung
showModal() öffnet ein <dialog>-Element als modalen Dialog. Der Dialog wird in die sogenannte Top Layer verschoben und liegt damit unabhängig von z-index oder overflow der Elternelemente über allen anderen Inhalten. Hinter dem Dialog wird das Pseudo-Element ::backdrop gerendert, das sich per CSS gestalten lässt, z. B. als halbtransparente Abdunkelung.
Solange der Dialog modal geöffnet ist, ist der restliche Dokumentinhalt inert: Er lässt sich weder anklicken noch per Tastatur fokussieren und ist für assistive Technologien ausgeblendet. Der Fokus springt automatisch auf das erste fokussierbare Element im Dialog (oder auf ein Element mit dem Attribut autofocus). Mit der Esc-Taste lässt sich der Dialog schließen. Dabei wird zuerst das Ereignis cancel und danach close ausgelöst.
Verwende showModal() für Bestätigungsabfragen, Formulare oder Hinweise, die die volle Aufmerksamkeit brauchen, bevor der Nutzer weiterarbeiten kann. Für nicht-modale Einblendungen, bei denen die Seite bedienbar bleiben soll, nimmst du show(). Geschlossen wird der Dialog mit close(returnValue) oder über ein Formular mit method="dialog".
Rückgabewert
undefined zurück. Unter bestimmten Bedingungen wird eine DOMException geworfen (siehe Hinweise).Beispiele
Modalen Dialog per Button öffnen und schließen
// HTML:
// <button id="open">Einstellungen</button>
// <dialog id="settings">
// <p>Einstellungen …</p>
// <button id="close">Schließen</button>
// </dialog>
const dialog = document.querySelector('#settings');
document.querySelector('#open').addEventListener('click', () => {
dialog.showModal();
console.log('offen:', dialog.open);
});
document.querySelector('#close').addEventListener('click', () => {
dialog.close();
console.log('offen:', dialog.open);
});
Bestätigungsdialog mit Promise und returnValue
// HTML:
// <dialog id="confirm">
// <form method="dialog">
// <p>Eintrag wirklich löschen?</p>
// <button value="cancel">Abbrechen</button>
// <button value="ok" autofocus>Löschen</button>
// </form>
// </dialog>
const confirmDialog = (dialog) =>
new Promise((resolve) => {
dialog.returnValue = '';
dialog.addEventListener(
'close',
() => resolve(dialog.returnValue === 'ok'),
{ once: true }
);
dialog.showModal();
});
const handleDelete = async () => {
const ok = await confirmDialog(document.querySelector('#confirm'));
console.log(ok ? 'Wird gelöscht' : 'Abgebrochen');
};
handleDelete();
Schließen per Klick auf den Backdrop und Esc abfangen
const dialog = document.querySelector('dialog');
dialog.showModal();
// Klick außerhalb des Inhalts trifft das <dialog>-Element selbst (Backdrop-Bereich)
dialog.addEventListener('click', (event) => {
const rect = dialog.getBoundingClientRect();
const inside =
event.clientX >= rect.left && event.clientX <= rect.right &&
event.clientY >= rect.top && event.clientY <= rect.bottom;
if (!inside) dialog.close('backdrop');
});
// Esc verhindern, z. B. bei ungespeicherten Änderungen
dialog.addEventListener('cancel', (event) => {
if (!confirm('Änderungen verwerfen?')) event.preventDefault();
});
dialog.addEventListener('close', () => {
console.log('Geschlossen mit:', dialog.returnValue);
});
Sicher öffnen, ohne Exception
const openModalSafely = (dialog) => {
if (!dialog.isConnected) return false;
if (dialog.open && !dialog.matches(':modal')) dialog.close();
if (!dialog.open) dialog.showModal();
return dialog.matches(':modal');
};
console.log(openModalSafely(document.querySelector('dialog')));
// Wichtig · Fallstricke
- Exceptions: Ist der Dialog bereits nicht-modal offen (über
show()oder das Attributopen), wirftshowModal()einenInvalidStateError. Das Gleiche passiert, wenn das Element nicht im Dokument hängt (isConnected === false) oder als Popover angezeigt wird. Ist der Dialog bereits modal offen, bleibt der Aufruf seit neueren Spezifikationsständen ohne Wirkung. - Nicht das Attribut
opensetzen: Mitdialog.open = trueoder<dialog open>öffnet sich der Dialog nur nicht-modal. Dann gibt es weder Top Layer noch::backdrop, kein Inert-Verhalten und kein Schließen per Esc. - Fokus: Beim Schließen geht der Fokus in modernen Browsern an das Element zurück, das vorher fokussiert war. Mit
autofocuslegst du fest, welches Element im Dialog den Anfangsfokus bekommt. Bei destruktiven Aktionen ist „Abbrechen“ als Anfangsfokus meist die sicherere Wahl. - Scrollen im Hintergrund: Die Seite hinter dem Dialog lässt sich weiter scrollen. Falls das stört, sperrst du es per CSS, z. B. mit
body:has(dialog[open]) { overflow: hidden; }. - Esc-Taste: Chrome lässt einen Dialog nicht dauerhaft offen, wenn der Nutzer mehrfach Esc drückt, auch wenn
cancelperpreventDefault()abgefangen wird. Verlasse dich nicht darauf, dass sich das Schließen vollständig verhindern lässt. - Kompatibilität: Seit Firefox 98 und Safari 15.4 (2022) in allen modernen Browsern verfügbar. Für ältere Browser gibt es das Polyfill
dialog-polyfill. Neuere Zusätze wie das Attributclosedbyoder deklarative Befehle (command="show-modal") werden noch nicht überall unterstützt.