Modale Dialoge ohne Framework – das native <dialog>-Element
Für ein Modal brauchst du kein Bibliotheks-Ballast und keine z-index-Schlacht. Das HTML-Element <dialog> bringt Overlay, Fokus-Falle und Schließen mit Escape von Haus aus mit. Ich zeige dir showModal(), ::backdrop und das saubere Schließen.
Jahrelang war ein Modal-Dialog im Web erstaunlich nervig: ein <div> mit position: fixed, ein Overlay dahinter, z-index-Gefummel, Tastatur-Fokus einfangen, Escape abfangen. Das kannst du dir heute sparen – das native <dialog>-Element macht das meiste selbst.
Das Markup
<dialog id="hinweis">
<form method="dialog">
<h2>Änderungen speichern?</h2>
<p>Deine Eingaben gehen sonst verloren.</p>
<menu>
<button value="abbrechen">Abbrechen</button>
<button value="speichern">Speichern</button>
</menu>
</form>
</dialog>
<button id="oeffnen">Dialog öffnen</button>Öffnen mit showModal()
const dlg = document.getElementById("hinweis");
document.getElementById("oeffnen").onclick = () => dlg.showModal();
dlg.addEventListener("close", () => {
console.log("Gewählt:", dlg.returnValue); // "speichern" oder "abbrechen"
});showModal() macht die eigentliche Arbeit: Es legt den Dialog oben auf die Seite (in die sogenannte Top-Layer, ganz ohne z-index), sperrt den Rest der Seite für Klicks, fängt den Tastatur-Fokus im Dialog und schließt bei Escape automatisch. Ein <form method="dialog"> schließt beim Absenden und schreibt den value des Buttons nach dialog.returnValue.
Das Overlay stylen mit ::backdrop
Den abgedunkelten Hintergrund gibt es gratis – du stylst ihn über das Pseudo-Element ::backdrop:
dialog {
border: none;
border-radius: 14px;
padding: 24px;
box-shadow: 0 20px 50px rgba(0,0,0,.25);
}
dialog::backdrop {
background: rgba(0,0,0,.5);
backdrop-filter: blur(2px);
}Wichtig: ::backdrop erscheint nur bei showModal(), nicht bei dialog.show() (nicht-modal, ohne Overlay).
Klick auf den Hintergrund schließt
Ein Detail, das Nutzer erwarten: Klick neben den Dialog schließt ihn. Das ist der einzige Teil, den du noch selbst ergänzt:
dlg.addEventListener("click", (e) => {
if (e.target === dlg) dlg.close(); // Klick traf das Backdrop, nicht den Inhalt
});<dialog> wird von allen aktuellen Browsern unterstützt. Weniger Code, bessere Barrierefreiheit (Fokus + Escape inklusive) – ich baue Modals in neuen Projekten nur noch so.
Quellen
Du brauchst mehr als ein Snippet?
Ich entwickle Android-Apps in Kotlin und moderne Websites für Selbstständige und kleine Unternehmen — von der ersten Idee bis zum Release.
Projekt anfragen →Verwandte Snippets
:is() und :where() – kürzere Selektoren, und einer davon wiegt nichts
Drei fast gleiche Selektoren untereinander, nur weil die Überschrift mal h2 und mal h3 heißt? :is() fasst das zusammen. Und :where() macht dasselbe, ohne die Spezifität hochzutreiben – der Unterschied ist der ganze Trick.
content-visibility – lange Seiten rendern, ohne dass der Browser alles auf einmal baut
Bei sehr langen Seiten rechnet der Browser Layout und Malen für jeden Abschnitt – auch für die, die 8.000 Pixel weiter unten liegen. Eine CSS-Eigenschaft verschiebt diese Arbeit auf den Moment, in dem sie gebraucht wird.
color-mix() – Hover- und Dark-Mode-Farben ausrechnen lassen, statt sie zu pflegen
Für jede Markenfarbe eine hellere, eine dunklere und eine transparente Variante von Hand zu pflegen, ist Fleißarbeit mit Fehlerquote. color-mix() mischt sie im Browser – aus genau einer Quellfarbe.