- Das HTML-
<dialog>-Element erstellt native modale und nicht-modale Dialoge im Browser; modale Dialoge versetzen den restlichen Seitenbereich in den Zustand inert und blockieren so Interaktionen.
- Zum Öffnen und Schließen dienen standardmäßig
showModal(), show() und close(); deklarative Steuerung ist außerdem über <form>, die Invoker Commands API und die Popover API möglich.
- Das Attribut
closedby unterteilt die Wege, auf denen Benutzer einen Dialog schließen können, in any, closerequest und none; das Standardverhalten hängt davon ab, wie der Dialog geöffnet wurde.
- Für die Barrierefreiheit sind der anfängliche Fokus und ein expliziter Schließen-Button wichtig; per
showModal() geöffnete Dialoge fokussieren standardmäßig das erste fokussierbare Element und lassen sich mit Esc schließen.
- Für das Styling werden
:modal, :open und ::backdrop verwendet; für Animationen sind diskrete Übergänge mit display, overlay, @starting-style und transition-behavior: allow-discrete nötig.
Die Rolle von <dialog> und modales Verhalten
- Das HTML-
<dialog>-Element dient zum Erstellen modaler und nicht-modaler Dialoge.
- Modale Dialoge verhindern die Interaktion mit anderen UI-Elementen und versetzen den Rest der Seite in den Zustand
inert.
- Mit nicht-modalen Dialogen kann auch im geöffneten Zustand weiter mit dem restlichen Seiteninhalt interagiert werden.
Öffnungszustand und Schließrichtlinien
<dialog> unterstützt globale Attribute, aber das Attribut tabindex darf nicht verwendet werden.
<dialog> selbst ist kein interaktives Element und erhält keinen Fokus.
- Interne Inhalte und Schließen-Buttons können fokussiert und bedient werden.
- Das Attribut
open zeigt an, dass der Dialog aktiv und interaktiv ist.
- Ohne
open ist er für Benutzer nicht sichtbar.
- Zum Anzeigen eines Dialogs wird
.show() oder .showModal() gegenüber dem open-Attribut empfohlen.
- Ein über das
open-Attribut geöffneter <dialog> ist nicht-modal.
- Der offene/geschlossene Zustand nicht-modaler Dialoge kann zwar durch Umschalten von
open geändert werden, empfohlen wird das jedoch nicht.
- Das Attribut
closedby legt fest, auf welche Weise Benutzer den Dialog schließen können.
any: Schließen über alle drei Wege möglich
- Light dismiss wie Klicken oder Tippen außerhalb des Dialogs
- plattformspezifische Aktionen wie die Esc-Taste, Zurück auf Mobilgeräten oder eine Dismiss-Geste
- vom Entwickler definierte Wege wie Buttons, die
HTMLDialogElement.close() aufrufen, oder das Absenden eines <form>
closerequest: Schließen über plattformspezifische Aktionen und vom Entwickler definierte Wege möglich
none: Schließen nur über vom Entwickler definierte Wege möglich
- Gibt es keinen gültigen
closedby-Wert, verhält sich ein mit showModal() geöffneter Dialog wie closerequest, alle anderen wie none.
JavaScript und deklarative Steuerung
- Anzeige und Schließen von
<dialog> können direkt per JavaScript gesteuert werden.
showModal(): zeigt einen modalen Dialog an
show(): zeigt einen nicht-modalen Dialog an
close(): schließt den Dialog
- Er kann auch geschlossen werden, indem ein
<form> innerhalb von <dialog> mit method="dialog" abgesendet wird.
- Modale Dialoge lassen sich außerdem mit der Esc-Taste schließen.
- Die Invoker Commands API ermöglicht das Öffnen und Schließen modaler Dialoge allein über Button-Attribute.
- Für
<button> werden die Attribute commandfor und command gesetzt.
- Für Dialoge verfügbare Befehle sind
"show-modal", "close" und "request-close".
Open dialog
This dialog was opened using an invoker command.
Close
- Die Popover API ermöglicht es, nicht-modale Dialoge deklarativ zu öffnen, zu schließen und umzuschalten.
- Durch Hinzufügen des Attributs
popover zu <dialog> wird es zu einem Popover.
- Für Buttons oder Eingabeelemente werden
popovertarget und popovertargetaction gesetzt.
- Popover-Dialoge sind nicht-modal und können daher durch Klicken außerhalb geschlossen werden.
- Wird kein Wert für
popover angegeben, gilt der Standardwert "auto", wodurch Light dismiss aktiviert wird.
popover="manual" deaktiviert Light dismiss und erfordert einen separaten Mechanismus wie einen Schließen-Button.
- Wird
popovertargetaction weggelassen, wird standardmäßig toggle verwendet.
Formularübermittlung und Schließen
- Jeder
<dialog> benötigt einen Schließmechanismus, der auch auf Geräten ohne physische Tastatur funktioniert.
- Es gibt verschiedene Möglichkeiten zum Schließen.
- Absenden eines internen
<form> mit method="dialog"
- Klicken außerhalb des Dialogs bei aktiviertem Light dismiss
- Drücken der Esc-Taste bei Dialogen, die dies erlauben
- Aufruf von
HTMLDialogElement.close()
method="dialog" bei <form> oder formmethod="dialog" bei einem Submit-Button schließt den Dialog.
- Der Zustand der Formularfelder bleibt erhalten, das Formular wird jedoch nicht abgeschickt.
returnValue wird auf den Wert des aktivierten Buttons gesetzt.
- Bei Formularen mit Pflichtfeldern verhindert der User Agent bei einer normalen Übermittlung das Schließen des Dialogs, bis Werte eingegeben wurden.
- Mit
formnovalidate auf dem Schließen-Button kann die Formularvalidierung umgangen werden.
- Auch ein Aufruf von
dialog.close() per JavaScript kann den Dialog schließen.
Fokus und Barrierefreiheit
- Wird
<dialog> mit showModal() geöffnet, erhält standardmäßig das erste verschachtelte fokussierbare Element den Fokus.
- Um in einem bestimmten Dialog die geeignetste anfängliche Fokusposition festzulegen, kann das Attribut
autofocus verwendet werden.
- Gibt es kein Element für eine sofortige Interaktion, empfiehlt es sich, den Schließen-Button mit
autofocus zu versehen.
- Bei Dialogen mit dynamisch gerendertem Inhalt, bei denen der anfängliche Fokus unklar ist, kann
<dialog> selbst eine geeignete Ausgangsposition sein.
- Am robustesten ist es, explizite Buttons wie Bestätigen-, Abbrechen- oder Schließen-Buttons bereitzustellen, damit alle Benutzer den Dialog schließen können.
- Mit
showModal() geöffnete Dialoge lassen sich standardmäßig per Esc schließen.
- Nicht-modale Dialoge lassen sich standardmäßig nicht mit Esc schließen.
- Tastaturnutzer erwarten bei modalen Dialogen, dass sie sich mit Esc schließen lassen.
- Sind mehrere modale Dialoge geöffnet, sollte Esc nur den zuletzt angezeigten Dialog schließen; bei Verwendung von
<dialog> stellt der Browser dieses Verhalten bereit.
- Das native
<dialog> bietet Funktionen für Bedienbarkeit und Barrierefreiheit, die bei benutzerdefinierten Dialogen auf Basis anderer Elemente manuell nachgebildet werden müssten.
- Browser stellen
<dialog> ähnlich wie benutzerdefinierte Dialoge mit ARIA role="dialog" bereit.
- Ein mit
showModal() aufgerufener <dialog> hat implizit aria-modal="true".
- Mit
show(), dem open-Attribut oder einer geänderten Standard-display-Eigenschaft angezeigte <dialog> werden als aria-modal="false" exponiert.
- Bei der Implementierung modaler Dialoge muss alles außer
<dialog> und seinem Inhalt als inert gerendert werden; bei Verwendung von showModal() übernimmt der Browser dies.
CSS-Styling und Backdrop
<dialog> kann wie ein normales Element über seinen Elementnamen ausgewählt werden.
- Für zustandsbasiertes Styling können die Pseudoklassen
:modal und :open verwendet werden.
- Der Hintergrund modaler Dialoge kann über das Pseudoelement
::backdrop gestaltet werden.
- Es wirkt auf den Backdrop, der hinter
<dialog> erscheint, wenn der Dialog mit showModal() angezeigt wird.
- Damit kann der inerte Hintergrundinhalt weichgezeichnet, abgedunkelt oder verdeckt werden.
Typische Nutzungsmuster in Beispielen
- Das Beispiel zur Invoker Commands API öffnet den Dialog mit einem
command="show-modal"-Button und schließt ihn mit einem command="close"-Button.
- Er lässt sich über den Button „Open dialog“ öffnen.
- Er lässt sich über den Button „Close“ oder mit Esc schließen.
- Das Beispiel zur Popover API öffnet und schließt einen nicht-modalen Dialog mit
popover, popovertarget und popovertargetaction.
- Er kann über den Button „Close“, mit Esc oder durch Auswahl außerhalb des Dialogs geschlossen werden.
- Mit
popover="manual" wird Light dismiss deaktiviert.
- Das Beispiel mit dem
open-Attribut erzeugt einen bereits beim Laden der Seite geöffneten, rein in HTML definierten nicht-modalen Dialog.
- Er kann über den „OK“-Button im
<form> geschlossen werden.
- Ein erneutes Öffnen nach dem Schließen ist nicht vorgesehen.
- Für die Anzeige nicht-modaler Dialoge wird
HTMLDialogElement.show() bevorzugt.
- Das Beispiel für einen modalen Dialog öffnet ihn mit
.showModal() und schließt ihn mit close().
- Der Hintergrund wird mit
::backdrop als Verlauf gestaltet.
- Ist der Dialog geöffnet, bleibt alles außerhalb davon inert und das Dokument kann nicht interaktiv genutzt werden.
- Das Beispiel zu
returnValue behandelt den Rückgabewert des Dialogs über Formular- und Button-Werte.
- Der Standardwert von
returnValue ist ein leerer String oder der Wert des Buttons, mit dem ein Formular im Dialog abgesendet wurde.
- Der Button „Confirm“ übergibt den Auswahlwert an
close() und verwendet ihn als Rückgabewert.
- Wird mit Esc geschlossen, wird
returnValue nicht aktualisiert und auch kein close-Event ausgelöst, sodass der <output>-Text nicht aktualisiert wird.
Animationen für <dialog>
- Ein ausgeblendeter
<dialog> hat display: none, ein sichtbarer <dialog> display: block.
- Beim Wechsel des Sichtbarkeitszustands wird das Element zur top layer und zum Accessibility Tree hinzugefügt oder daraus entfernt.
- Um
<dialog> zu animieren, muss die Eigenschaft display animierbar sein.
- Unterstützende Browser behandeln
display als diskrete Animation.
- Beim Wechsel von
none zu block wird bereits bei 0 % auf block umgeschaltet, sodass der Dialog während der gesamten Animation sichtbar ist.
- Beim Wechsel von
block zu none wird erst bei 100 % auf none umgeschaltet, sodass er während der gesamten Animation sichtbar bleibt.
-
Animation mit CSS-Transitions
- Um
<dialog> mit CSS-Transitions zu animieren, sind die folgenden Funktionen erforderlich.
@starting-style: liefert den Startwert der Transition bei jedem Öffnen des Dialogs
display-Transition: hält den Dialog während der Transition auf einem sichtbaren display-Wert
overlay-Transition: verzögert das Entfernen aus der top layer bis zum Abschluss der Transition
transition-behavior: allow-discrete: aktiviert diskrete Transitions für standardmäßig nicht animierbare Eigenschaften wie display und overlay
- In Browsern ohne Unterstützung für die Pseudoklasse
:open kann der offene Zustand über den Attributselektor dialog[open] gestylt werden.
- Da
<dialog> bei jeder Anzeige von display: none auf display: block wechselt, erfolgt bei jeder Eintrittsanimation der Übergang von @starting-style zum Stil von dialog:open.
-
Keyframe-Animationen
- CSS-Keyframe-Animationen unterliegen anderen Einschränkungen als Transitions.
- Sie bieten kein
@starting-style.
- Der
display-Wert wird innerhalb der Keyframes angegeben.
allow-discrete muss nicht explizit aktiviert werden.
overlay muss ebenfalls nicht in den Keyframes gesetzt werden.
- Ein Fade-out des Backdrops ist beim Schließen nicht animierbar, weil der Backdrop sofort aus dem DOM entfernt wird.
Technische Zusammenfassung
- Inhaltskategorien: flow content, sectioning root
- Erlaubter Inhalt: flow content
- Start- und End-Tag sind beide erforderlich; Tag-Auslassung ist nicht erlaubt.
- Erlaubte Eltern: alle Elemente, die flow content akzeptieren
- Implizite ARIA-Rolle:
dialog
- Erlaubte ARIA-Rolle:
alertdialog
- DOM-Schnittstelle:
HTMLDialogElement
- Spezifikation: HTML # the-dialog-element
1 Kommentare
Meinungen auf Hacker News
Zu interaktiven HTML-Elementen gehören etwa Dateiauswahl, Farbauswahl, Datum-/Uhrzeit-Auswahl, Zahlen-Slider, Vorschlagsoptionen in Textfeldern, aufklappbare Zusammenfassungen/Details, FAQs und Media Player mit Controls.
Solche Elemente sind leichtgewichtig und semantisch, was gut ist; außerdem können
<details>-Elemente, die denselbennameteilen, sich so verhalten, dass beim Öffnen eines Eintrags der vorherige geschlossen wird.Es wäre schön, wenn das besser umgesetzt wäre.
Ich habe
<dialog>seit 2019 verwendet; obwohl Firefox und Safari es noch einige Jahre lang nicht unterstützten, war Googles Polyfill so gut, dass wir es in einer SaaS-Produktion für Geschäftskunden ohne Probleme einsetzen konnten.Am enttäuschendsten war, dass das Element kaum gestylt war. Es hatte nur einen sehr einfachen, dicken schwarzen Pixelrahmen und eckige Kanten – anders als erwartet, dass der Browser den Dialog-/Fensterplatzierungs-Konventionen des Betriebssystems folgen und es wie native Dialoge unter macOS, iOS oder Windows aussehen lassen würde.
Da sich das geöffnete Element in einer separaten obersten Ebene befindet, hatte ich auch gehofft, dass es sich außerhalb des Browser-Viewports bewegen könnte; auch diese Erwartung wurde enttäuscht. Aus Nutzersicht will man schließlich kein unbewegliches Popup oder modales Dialogfenster, das den Dokumentinhalt vollständig verdeckt.
Die Browser-Anbieter scheinen zu wollen, dass man
alert(),prompt()undconfirm()nicht mehr verwendet, weil sie JavaScript bzw. den Main Thread blockieren; sie haben aber keine Ersatz-API geliefert, die ähnlich einfach und effektiv ist und keine UI-Design-Fähigkeiten erfordert. Statt zu versuchen, uns davon zu überzeugen, dass<dialog>in jeder Situation besser ist, wäre eine Promise-basierte, nicht blockierende alert/prompt/confirm-API wünschenswert.Dass neue Funktionen sich nicht mehr wie die alte
alert()-Familie verhalten, ist nicht nur eine zufällige Enttäuschung, sondern hat auch Vorteile.Allerdings hätte man den Standardstil von
<dialog>etwas sorgfältiger gestalten müssen; selbst wenn es nicht zu 100 % wie ein Systemdialog außerhalb des DOM aussieht und funktioniert, wäre schon ein Standardstil, der zu den Browser-Defaults passt, deutlich besser gewesen.Bei Web-Apps mit mehr Berechtigungen als normale Seiten, etwa PWAs, könnte eine solche Richtung eher akzeptiert werden – ähnlich wie separate Funktionen für Fenster-Styling oder Interaktion mit dem System.
<dialog>wie ein natives Browserfenster aussehen lässt, kann das die line of death verwischen.Es würde bösartigen Websites erleichtern, mitten auf der Seite ein „Browser-Update“-Popup anzuzeigen und auf eine plausibel wirkende Chrome-Downloadseite umzuleiten, über die dann eine manipulierte ausführbare Datei heruntergeladen wird.
https://textslashplain.com/2017/01/14/the-line-of-death/
Nutzer haben mehrere Tabs geöffnet, und in einem anderen Tab könnten sich Informationen befinden, die sie zum Abschließen des Dialogs benötigen.
Außerdem muss man sehr vorsichtig sein, wie viel visuelle Kontrolle man tatsächlichen Dialogen gibt. Insbesondere wenn sie wie das Betriebssystem aussehen, könnte das die Erfolgsquote von Angriffen stark erhöhen: Schon heute fallen viele Menschen auf gefälschte Browser-Virenwarnungen herein; Dialoge, die echt aussehen und mit denen man zwingend interagieren muss, wären noch gefährlicher.
Die meisten Firmen, bei denen ich gearbeitet habe, hatten in irgendeiner Form eine konsistente Designsprache, und egal, was Befürworter von reinem HTML/CSS sagen: Wenn man eingebaute Browser-Komponenten unverändert verwendet, wirkt das meistens amateurhaft und unpassend.
Solange dieses Problem nicht gelöst ist, wird es schwer, eine breite Nutzung zu erreichen.
alert(),prompt()undconfirm()so funktionieren zu lassen wieawait Prompts.alert("This is an alert message!");,await Prompts.confirm(...)undawait Prompts.prompt(...).Demo: https://tools.simonwillison.net/prompts-js
Der Code wurde von o1 geschrieben: https://chatgpt.com/share/67539c28-4df0-8006-b021-4f468e011f...
Ich habe den Beitrag „The HTML dialog element API is a mess“ geschrieben: https://lapcatsoftware.com/articles/2024/2/1.html
Trotzdem liegt ihr Wert darin, dass sie Standards sind. Das Web ist großartig, weil es überall funktioniert, und zwangsläufig unordentlich.
In diesem Kontext halte ich
<dialog>für einen Erfolg, besonders bei internen Verwaltungstools. Man will sich nicht um die neuesten Frontend-Trends kümmern, sondern einfach Bildschirmfläche sparen und Inhalte als modales Overlay über der Hauptansicht anzeigen.Um einen Dialog zu öffnen, ist eine Benutzereingabe nötig, und ein modaler Dialog blockiert Benutzereingaben; damit das passiert, müsste also eine Eingabe innerhalb des Dialogs denselben Dialog erneut öffnen.
Wenn man einen Dialog über eine asynchrone Aktion öffnet, muss man nachverfolgen, was geöffnet und geschlossen ist; Ähnliches passiert auch in Umgebungen wie Qt.
<dialog>zu einer anpassbaren aufgewerteten Variante von await confirm/prompt wird, bei der auch mehrfaches Öffnen nicht je nach Browser Warnungen auslöst.Tatsächlich ist es aber eher ein aufgehübschtes
div.Die Compression Streams API war nicht schlecht, aber eine sehr kleine API.
Wenn man sich das Muster ansieht, scheint Google nicht besonders gut mit User Experience und Developer Experience umzugehen.
Nebenbei habe ich die Standardpositionen nachgeschlagen: Beide unterstützen URLPattern.
Unabhängig von der Implementierung halte ich es für einen Schritt in die richtige Richtung.
Derzeit gibt es auch einen Vorschlag, der wie eine Erweiterung von
<select>wirkt: https://open-ui.org/components/combobox.explainer/Für Toast-Benachrichtigungen ist die Popover API bereits im Browser angekommen: https://mdn.github.io/dom-examples/popover-api/
Außerdem gibt es einen Vorschlag für Popover Hints für Tooltips: https://open-ui.org/components/popover-hint.research.explain...
Ich mag das Element
<dialog>, besonders die eingebauten und standardisierten Überlegungen zur Barrierefreiheit.Ich freue mich auf den Tag, an dem man es ohne Polyfill verwenden kann, sobald Safari vor 15.4 aus den Support-Anforderungen herausfällt.
Mein größter Kritikpunkt ist allerdings die Abhängigkeit von JavaScript. Fast alle Website-Besucher werden JavaScript aktiviert haben, aber es kann auch befriedigend sein, dafür zu sorgen, dass es nicht zwingend nötig ist.
Ich verstehe nicht, warum man den geöffneten Zustand eines Dialogs nicht per CSS oder über einen Ziel-Button steuern kann; falls ich mich irre, würde ich das gern wissen.
popover="".Sie lassen sich leicht per Button ansteuern, benötigen kein clientseitiges JavaScript und können auch durch Klicken außerhalb geschlossen werden. Dieses Verhalten hat
<dialog>standardmäßig nicht.Bei der Barrierefreiheit bin ich mir nicht sicher, aber es dürfte nicht schlechter sein als die früheren Ansätze mit versteckten Labels/Checkboxes/Formularelementen, und es ist deutlich einfacher und fühlt sich weniger nach Hack an.
https://css-tricks.com/invoker-commands-additional-ways-to-w...
Es wäre schön, wenn HTML ein Konzept wie ein
<page>-Tag unterstützen würde, mit dem man mehrere Seiten in einer einzigen Datei definieren und jeweils nur eine davon anzeigen kann.Ohne dass es wie ein Dialog aussieht, sollten gemeinsame Bereiche wie Header, Sidebar und Footer innerhalb derselben Seite je nach ausgewählter PAGE eingebunden werden können.
Schon heute kann man das durch Ein- und Ausblenden von
divs machen, aber ein spezielles HTML-Tag, das diesen Ansatz unterstützt, könnte hilfreich sein.Ich bin heute beim Ausprobieren auf ein Problem gestoßen, für das ich keinen Workaround gefunden habe.
Wenn sich in einem Dialog ein Formular befindet, wird beim Drücken von Enter in einem fokussierten Eingabefeld oder von Space auf einem fokussierten Submit-Button zusammen mit dem Absenden des Formulars auch der Dialog geschlossen.
Ich habe keine saubere Möglichkeit gefunden, das zu verhindern. Normalerweise lädt ein Formular die Seite neu, daher ist das wohl kein übliches Problem, aber hier habe ich htmx verwendet.
Ich verwende einen Editor, bei dem ein Formular in einem
<dialog>ein iframe aktualisiert; dabei wird nur das Ziel-iframe neu geladen, der Dialog aber nicht geschlossen.Ich konnte auch nicht reproduzieren, dass der Dialog beim Drücken von Enter geschlossen wird. Es sollte dasselbe wie
submitsein, und auchsubmitschließt den Dialog nicht.Nebenbei habe ich gestern gelernt, dass Buttons einen Dialog schließen können.
preventDefaultundstopPropagationnicht reichen?Auf der Suche nach einem Cookie-Consent-Manager für einen neu optimierten Build gefiel mir nicht, dass die Open-Source-Optionen über 100 KB groß waren, also habe ich selbst einen gebaut: https://github.com/replete/biscuitman
Um ihn so klein wie möglich zu halten, habe ich auf
<dialog>gesetzt; mit nur ein paar CSS-Regeln funktioniert er auch ohne eigenes Styling nativ.Am Ende habe ich sogar ein Build-Tool geschrieben, das bis hinunter zu IE11 und wirklich alten Browserversionen kompiliert.
<dialog>funktioniert im Großen und Ganzen gut, und in alten Browsern braucht es ein paar CSS-Tricks, ist aber nicht schwer zu handhaben. Es ist eine ordentliche Ergänzung der Webplattform, aber nach 20 Jahren in diesem Bereich möchte ich nicht alle paar Jahre wieder ein eigenes Multi-Select-Control bauen. Native Controls sind gut.Das übliche Schließverhalten der meisten Beispiele funktioniert in Android Firefox nicht
autofocus-Attribut des Schließen-Buttons nichtAm Ende habe ich jedes Mal beim Aufruf von
show()eine Zeile wie$('#thatModal *[autofocus]').focus()hinzugefügtLaut MDN sollte es standardmäßig wie beabsichtigt funktionieren
Es scheint, als würden nur per JavaScript hinzugefügte Listener korrekt funktionieren