This dialog was opened using an invoker command.
Non-modal dialogs using popover commands
Non-modal dialogs can be declaratively opened, closed, and toggled using the
Popover API
HTML attributes
popovertarget
and
popovertargetaction
, which can be defined on
This dialog was opened using a popovertargetaction attribute.
The Popover API also provides properties that can be used to get and set the state in JavaScript.
Closing dialogs
It is important to provide a closing mechanism for every
element, and to ensure that this works on devices that might not have a physical keyboard.
There are numerous ways to close a dialog:
Submitting the form within the
element with
method="dialog"
set on the
element (see the
Using the dialog open attribute
example).
Clicking outside the dialog area when "light dismiss" is enabled (see the
Popover API HTML attributes
example).
Pressing the
Esc
key, in dialogs where it is enabled (see the
Popover API HTML attributes
example).
Calling the
HTMLDialogElement.close()
method (see the
modal example
).
CSS Styling
can be selected using its element name (like any other element), and you can also match its state using pseudo-classes such as
:modal
and
:open
The CSS
::backdrop
pseudo-element can be used to style the backdrop of a modal dialog, which is displayed behind the
element when the dialog is displayed using the
HTMLDialogElement.showModal()
method.
This pseudo-element could be used, for example, to blur, darken, or otherwise obfuscate the inert content behind the modal dialog.
Additional notes
HTML
elements can be used to close a dialog box if they have the attribute
method="dialog"
or if the button used to submit the form has
formmethod="dialog"
set. When a
within a
is submitted via the
dialog
method, the dialog box closes, the states of the form controls are saved but not submitted, and the
returnValue
property gets set to the value of the button that was activated.
The
autofocus
attribute should be added to the element the user is expected to interact with immediately upon opening a modal dialog. If no other element involves more immediate interaction, it is recommended to add
autofocus
to the close button inside the dialog, or the dialog itself if the user is expected to click/activate it to dismiss.
Do not add the
tabindex
property to the
element as it is not interactive and does not receive focus. The dialog's contents, including the close button contained in the dialog, can receive focus and be interactive.
When implementing a dialog, it is important to consider the most appropriate place to set user focus. When using
HTMLDialogElement.showModal()
to open a
, focus is set on the first nested focusable element. Explicitly indicating the initial focus placement by using the
autofocus
attribute will help ensure initial focus is set on the element deemed the best initial focus placement for any particular dialog. When in doubt, as it may not always be known where initial focus could be set within a dialog, particularly for instances where a dialog's content is dynamically rendered when invoked, the
element itself may provide the best initial focus placement.
Ensure a mechanism is provided to allow users to close the dialog. The most robust way to ensure that all users can close the dialog is to include an explicit button to do so, such as a confirmation, cancellation, or close button.
By default, a dialog invoked by the
showModal()
method can be dismissed by pressing the
Esc
key. A non-modal dialog does not dismiss via the
Esc
key by default, and depending on what the non-modal dialog represents, it may not be desired for this behavior. Keyboard users expect the
Esc
key to close modal dialogs; ensure that this behavior is implemented and maintained. If multiple modal dialogs are open, pressing the
Esc
key should close only the last shown dialog. When using
, this behavior is provided by the browser.
While dialogs can be created using other elements, the native
element provides usability and accessibility features that must be replicated if you use other elements for a similar purpose. If you're creating a custom dialog implementation, ensure that all expected default behaviors are supported and proper labeling recommendations are followed.
The
element is exposed by browsers in a manner similar to custom dialogs that use the ARIA
role="dialog"
attribute.
elements invoked by the
showModal()
method implicitly have
aria-modal="true"
, whereas
elements invoked by the
show()
method or displayed using the
open
attribute or by changing the default
display
of a
are exposed as
[aria-modal="false"]
. When implementing modal dialogs, everything other than the
and its contents should be rendered inert using the
inert
attribute. When using
along with the
HTMLDialogElement.showModal()
method, this behavior is provided by the browser.
Examples
Invoker Command API HTML attributes
This example demonstrates how you can use open and close a modal dialog using the
commandfor
and
command
HTML attributes of the
Invoker Commands API
First, we declare a
element, setting the
command
attribute to
"show-modal"
, and the
commandfor
attribute to the
id
of the dialog to open (
my-dialog
).
Then we declare a
element that contains a "Close"
. This button sends the
"close"
command to the (same) dialog id.
html
This dialog was opened using an invoker command.
Result
Open the dialog by pressing the "Open dialog" button.
You can close the dialog by selecting the "Close" button or pressing the
Esc
key.
Popover API HTML attributes
This example demonstrates how you can open and close a non-modal dialog using the
popover
popovertarget
, and
popovertargetaction
HTML attributes of the
Popover API
The
is turned into a popover by adding the
popover
attribute.
Since we haven't specified a value for the attribute, the default value of
"auto"
is used.
This enables "light dismiss" behavior, allowing the dialog to be closed by clicking outside the dialog or by pressing
Esc
We could instead have set
popover="manual"
to disable "light dismiss" behavior, in which case the dialog would have to be closed using the "Close" button.
Note that we haven't specified the
popovertargetaction
attribute for the
that opens the dialog.
It isn't needed in this case, because its default value is
toggle
, which will toggle the dialog between its open and closed states when the button is clicked.
html
This dialog was opened using a popovertargetaction attribute. Greetings, one and all! This modal dialog has a groovy backdrop!
Result
Open the dialog by pressing the "Open dialog" button.
You can close the dialog by selecting the "Close" button or pressing the
Esc
key.
You can also close it by selecting outside the dialog, as it is non-modal.
Using the dialog
open
attribute
This example demonstrates how you can set the boolean
open
attribute on a
element, in order to create an HTML-only non-modal dialog that is already open when the page loads.
The dialog can be closed by clicking the "OK" button because the
method
attribute in the
element is set to
"dialog"
In this case, no JavaScript is needed to close the form.
html
Result
This dialog is initially open and non-modal because of the presence of the
open
attribute.
After clicking "OK", the dialog gets dismissed, leaving the Result frame empty.
Note:
Reload the page to reset the output.
When the dialog is dismissed, there is no method provided to reopen it. The preferred method to display non-modal dialogs is to use the
HTMLDialogElement.show()
method.
It is possible to toggle the display of the dialog by adding or removing the boolean
open
attribute, but this is not the recommended practice.
Creating a modal dialog
This example demonstrates a modal dialog with a
gradient
backdrop. The
.showModal()
method opens the modal dialog when the "Show the dialog" button is activated. The dialog can be closed by pressing the
Esc
key or via the
close()
method when the "Close" button within the dialog is activated.
When a dialog opens, the browser, by default, gives focus to the first element that can be focused within the dialog. In this example, the
autofocus
attribute is applied to the "Close" button, giving it focus when the dialog opens, as this is the element we expect the user will interact with immediately after the dialog opens.
HTML
html
CSS
We can style the backdrop of the dialog by using the
::backdrop
pseudo-element.
css
::backdrop {
background-image: linear-gradient(
45deg,
magenta,
rebeccapurple,
dodgerblue,
green
);
opacity: 0.75;
JavaScript
The dialog is opened modally using the
.showModal()
method and closed using the
.close()
or
.requestClose()
methods.
js
const dialog = document.querySelector("dialog");
const showButton = document.querySelector("dialog + button");
const closeButton = document.querySelector("dialog button");
// "Show the dialog" button opens the dialog modally
showButton.addEventListener("click", () => {
dialog.showModal();
});
// "Close" button closes the dialog
closeButton.addEventListener("click", () => {
dialog.close();
});
Result
When the modal dialog is displayed, it appears above any other dialogs that might be present. Everything outside the modal dialog is inert and interactions outside the dialog are blocked. Notice that when the dialog is open, with the exception of the dialog itself, interaction with the document is not possible; the "Show the dialog" button is mostly obfuscated by the almost opaque backdrop of the dialog and is inert.
Handling the return value from the dialog
This example demonstrates the
returnValue
of the
element and how to close a modal dialog by using a form. By default, the
returnValue
is the empty string or the value of the button that submits the form within the
element, if there is one.
This example opens a modal dialog when the "Show the dialog" button is activated. The dialog contains a form with a
// "Show the dialog" button opens the
showButton.addEventListener("click", () => {
favDialog.showModal();
});
// "Cancel" button closes the dialog without submitting because of [formmethod="dialog"], triggering a close event.
favDialog.addEventListener("close", (e) => {
outputBox.value =
favDialog.returnValue === "default"
? "No return value."
: `ReturnValue: ${favDialog.returnValue}.`; // Have to check for "default" rather than empty string
});
// Prevent the "confirm" button from the default behavior of submitting the form, and close the dialog with the `close()` method, which triggers the "close" event.
confirmBtn.addEventListener("click", (event) => {
event.preventDefault(); // We don't want to submit this fake form
favDialog.close(selectEl.value); // Have to send the select box value here.
});
Result
Closing a dialog with a required form input
When a form inside a dialog has a required input, the user agent will only let you close the dialog once you provide a value for the required input. To close such dialog, either use the
formnovalidate
attribute on the close button or call the
close()
method on the dialog object when the close button is clicked.
html
type="submit"
id="novalidate-close"
value="Novalidate close"
formnovalidate />
[type="submit"] {
margin-right: 1rem;
JavaScript
js
const showBtn = document.getElementById("show-dialog");
const dialog = document.getElementById("dialog");
const jsCloseBtn = dialog.querySelector("#js-close");
showBtn.addEventListener("click", () => {
dialog.showModal();
});
jsCloseBtn.addEventListener("click", (e) => { Choose a
e.preventDefault();
dialog.close();
});
Result
From the output, we see it is impossible to close the dialog using the
Normal close
button. But the dialog can be closed if we bypass the form validation using the
formnovalidate
attribute on the
Cancel
button. Programmatically,
dialog.close()
will also close such dialog.
Comparison of different closedby behaviors
This example demonstrates the difference in behavior between different values of the
closedby
attribute.
HTML
We provide three
elements and three
elements. Each button will be programmed to open a different dialog that demonstrates the behavior of one of the three values of the
closedby
attribute —
none
closerequest
, and
any
. Note that each
element contains a
element that will be used to close it.
html<dialog> type to show:closedby="none"closedby="closerequest"closedby="any"
closedby="none"
Only closable using a specific provided mechanism, which in this case is
pressing the "Close" button below.
Closable using the "Close" button or the Esc key.closedby="closerequest"
closedby="any"
Closable using the "Close" button, the Esc key, or by clicking outside the
dialog. "Light dismiss" behavior.
body {
font-family: sans-serif;
#controls {
display: flex;
justify-content: space-around;
dialog {
width: 480px;
border-radius: 5px;
border-color: rgb(0 0 0 / 0.3);
dialog h2 {
margin: 0;
dialog p {
line-height: 1.4;
JavaScript
Here we assign different variables to reference the main control
elements, the
elements, and the "Close"
elements inside the dialogs. First we assign a
click
event listener to each control button using
addEventListener
, the event handler function of which opens the associated
element via
showModal()
. We then loop through the "Close"
references, assigning each one a
click
event handler function that closes its
element via
close()
js
const noneBtn = document.getElementById("none-btn");
const closerequestBtn = document.getElementById("closerequest-btn");
const anyBtn = document.getElementById("any-btn");
const noneDialog = document.querySelector("[closedby='none']");
const closerequestDialog = document.querySelector("[closedby='closerequest']");
const anyDialog = document.querySelector("[closedby='any']");
const closeBtns = document.querySelectorAll(".close");
noneBtn.addEventListener("click", () => {
noneDialog.showModal();
});
closerequestBtn.addEventListener("click", () => {
closerequestDialog.showModal();
});
anyBtn.addEventListener("click", () => {
anyDialog.showModal();
});
closeBtns.forEach((btn) => {
btn.addEventListener("click", () => {
btn.parentElement.close();
});
});
Result
The rendered result is as follows:
Try clicking each button to open a dialog. The first one can only be closed by clicking its "Close" button. The second one can also be closed via a device-specific user action such as pressing the
Esc
key. The third one has full
"light-dismiss" behavior
, so it can also be closed by clicking or tapping outside the dialog.
Animating dialogs
s are set to
display: none;
when hidden and
display: block;
when shown, as well as being removed from / added to the
top layer
and the
accessibility tree
. Therefore, for
elements to be animated the
display
property needs to be animatable.
Supporting browsers
animate
display
with a variation on the
discrete animation type
. Specifically, the browser will flip between
none
and another value of
display
so that the animated content is shown for the entire animation duration.
So for example:
When animating
display
from
none
to
block
(or another visible
display
value), the value will flip to
block
at
0%
of the animation duration so it is visible throughout.
When animating
display
from
block
(or another visible
display
value) to
none
, the value will flip to
none
at
100%
of the animation duration so it is visible throughout.
Note:
When animating using
CSS transitions
transition-behavior: allow-discrete
needs to be set to enable the above behavior. This behavior is available by default when animating with
CSS animations
; an equivalent step is not required.
Transitioning dialog elements
When animating
s with CSS transitions, the following features are required:
@starting-style
at-rule
Provides a set of starting values for properties set on the
that you want to transition from every time it is opened. This is needed to avoid unexpected behavior. By default, CSS transitions only occur when a property changes from one value to another on a visible element; they are not triggered on elements' first style updates, or when the
display
type changes from
none
to another type.
display
property
Add
display
to the transitions list so that the
will remain as
display: block
(or another visible
display
value set on the dialog's open state) for the duration of the transition, ensuring the other transitions are visible.
overlay
property
Include
overlay
in the transitions list to ensure the removal of the
from the top layer is deferred until the transition completes, again ensuring the transition is visible.
transition-behavior
property
Set
transition-behavior: allow-discrete
on the
display
and
overlay
transitions (or on the
transition
shorthand) to enable discrete transitions on these two properties that are not by default animatable.
Here is a quick example to show what this might look like.
HTML
The HTML contains a
element, plus a button to show the dialog. Additionally, the
element contains another button to close itself.
html
Content here
CSS
In the CSS, we include a
@starting-style
block that defines the transition starting styles for the
opacity
and
transform
properties, transition end styles on the
dialog:open
state, and default styles on the default
dialog
state to transition back to once the
has appeared. Note how the
's
transition
list includes not only these properties, but also the
display
and
overlay
properties, each with
allow-discrete
set on them.
We also set a starting style value for the
background-color
property on the
::backdrop
that appears behind the
when it opens, to provide a nice darkening animation. The
dialog:open::backdrop
selector selects only the backdrops of
elements when the dialog is open.
css
/* Open state of the dialog */
dialog:open {
opacity: 1;
transform: scaleY(1);
/* Closed state of the dialog */
dialog {
opacity: 0;
transform: scaleY(0);
transition:
opacity 0.7s ease-out,
transform 0.7s ease-out,
overlay 0.7s ease-out allow-discrete,
display 0.7s ease-out allow-discrete;
/* Equivalent to
transition: all 0.7s allow-discrete; */
/* Before open state */
/* Needs to be after the previous dialog:open rule to take effect,
as the specificity is the same */
@starting-style {
dialog:open {
opacity: 0;
transform: scaleY(0);
/* Transition the :backdrop when the dialog modal is promoted to the top layer */
dialog::backdrop {
background-color: transparent;
transition:
display 0.7s allow-discrete,
overlay 0.7s allow-discrete,
background-color 0.7s;
/* Equivalent to
transition: all 0.7s allow-discrete; */
dialog:open::backdrop {
background-color: rgb(0 0 0 / 25%);
/* This starting-style rule cannot be nested inside the above selector
because the nesting selector cannot represent pseudo-elements. */
@starting-style {
dialog:open::backdrop {
background-color: transparent;
Note:
In browsers that don't support the
:open
pseudo-class, you can use the attribute selector
dialog[open]
to style the
element when it is in the open state.
JavaScript
The JavaScript adds event handlers to the show and close buttons causing them to show and close the
when they are clicked:
js
const dialogElem = document.getElementById("dialog");
const showBtn = document.querySelector(".show");
const closeBtn = document.querySelector(".close");
showBtn.addEventListener("click", () => {
dialogElem.showModal();
});
closeBtn.addEventListener("click", () => {
dialogElem.close();
});
Result
The code renders as follows:
Note:
Because
s change from
display: none
to
display: block
each time they are shown, the
transitions from its
@starting-style
styles to its
dialog:open
styles every time the entry transition occurs. When the
closes, it transitions from its
dialog:open
state to the default
dialog
state.
It is possible for the style transition on entry and exit to be different in such cases. See our
Demonstration of when starting styles are used
example for a proof of this.
dialog keyframe animations
When animating a
with CSS keyframe animations, there are some differences to note from transitions:
You don't provide a
@starting-style
You include the
display
value in a keyframe; this will be the
display
value for the entirety of the animation, or until another non-
none
display value is encountered.
You don't need to explicitly enable discrete animations; there is no equivalent to
allow-discrete
inside keyframes.
You don't need to set
overlay
inside keyframes either; the
display
animation handles the animation of the
from shown to hidden.
Let's have a look at an example so you can see what this looks like.
HTML
First, the HTML contains a
element, plus a button to show the dialog. Additionally, the
element contains another button to close itself.
html
Content here
CSS
The CSS defines keyframes to animate between the closed and shown states of the
, plus the fade-in animation for the
's backdrop. The
animations include animating
display
to make sure the actual visible animation effects remain visible for the whole duration. Note that it wasn't possible to animate the backdrop fade out — the backdrop is immediately removed from the DOM when the
is closed, so there is nothing to animate.
css
dialog {
animation: fade-out 0.7s ease-out;
dialog:open {
animation: fade-in 0.7s ease-out;
dialog:open::backdrop {
background-color: black;
animation: backdrop-fade-in 0.7s ease-out forwards;
/* Animation keyframes */
@keyframes fade-in {
0% {
opacity: 0;
transform: scaleY(0);
display: none;
100% {
opacity: 1;
transform: scaleY(1);
display: block;
@keyframes fade-out {
0% {
opacity: 1;
transform: scaleY(1);
display: block;
100% {
opacity: 0;
transform: scaleY(0);
display: none;
@keyframes backdrop-fade-in {
0% {
opacity: 0;
100% {
opacity: 0.25;
body,
button {
font-family: system-ui;
JavaScript
Finally, the JavaScript adds event handlers to the buttons to enable showing and closing the
js
const dialogElem = document.getElementById("dialog");
const showBtn = document.querySelector(".show");
const closeBtn = document.querySelector(".close");
showBtn.addEventListener("click", () => {
dialogElem.showModal();
});
closeBtn.addEventListener("click", () => {
dialogElem.close();
});
Result
The code renders as follows:
Technical summary
Content categories
Flow content
sectioning root
Permitted content
Flow content
Tag omission
None, both the starting and ending tag are mandatory.
Permitted parents
Any element that accepts
flow content
Implicit ARIA role
dialog
Permitted ARIA roles
alertdialog
DOM interface
HTMLDialogElement
Specifications
Specification
HTML
# the-dialog-element
Browser compatibility
See also
HTMLDialogElement
interface
close
event of the
HTMLDialogElement
interface
cancel
event of the
HTMLDialogElement
interface
open
property of the
HTMLDialogElement
interface
inert
global attribute for HTML elements
::backdrop
CSS pseudo-element
Web forms
in the Learn area
Help improve MDN
Learn how to contribute
This page was last modified on
Feb 19, 2026
by
MDN contributors
View this page on GitHub
Report a problem with this content