Introducing the Dialog Element

Although the alert, confirm and prompt JavaScript methods are convenient, they aren’t recommended due to their script-blocking behavior. That’s why we worked with other browser vendors to drive improvements to the <dialog> specification over the last few years. The most important conversations involved accessibility.

You can find more complex use-cases, like payment dialogs, on the web. They are currently addressed by custom solutions from frameworks like Bootstrap. Unfortunately, they aren’t convenient to use and aren’t always accessible. We believe the web deserves a simple and bug-free solution for these use-cases. Safari Technology Preview 134 and Safari 15.4 beta introduces the <dialog> element for this reason!

How Do I Use <dialog>?

Let’s create a simple confirmation dialog:

<dialog id="confirmation-dialog">
    <h1>Do you want to delete everything?</h1>
    <p>You will lose all your data.</p>
    <button id="cancel-delete">Cancel</button>
    <button id="confirm-delete">Delete!</button>
</dialog>

Dialogs are hidden by default. We can use the showModal() method to show the dialog. When it’s shown, the dialog can be closed with the close() method.

Here is an example:

<button id="delete">Delete everything</button>
<p id="result"></p>
<script>
let dialog = document.getElementById("confirmation-dialog");
let result = document.getElementById("result");

// Show the dialog when clicking "Delete everything"
document.getElementById("delete").addEventListener("click", function() {
    dialog.showModal();
});

document.getElementById("cancel-delete").addEventListener("click", function() {
    dialog.close();
    result.textContent = "Canceled!";
});
document.getElementById("confirm-delete").addEventListener("click", function() {
    dialog.close();
    result.textContent = "Deleted!";
});
</script>

Note that the dialog will get an open attribute once opened, which may be useful for styling purposes. However, it’s not recommended to toggle this attribute manually to show or hide the dialog, since the browser may lose track of the dialog state, and will not perform proper focus adjustments for accessibility.

Example confirmation dialog

Modal and Non-modal Dialogs

In the last example, the showModal() method was used to create a modal dialog. User interaction is locked inside modal dialogs and outside content cannot be clicked, focused, selected, edited, or seen by accessibility tools. Another feature of modal dialogs is their ability to appear on top of everything else in the web page, regardless of the z-index of other elements.

Non-modal dialogs also exist and can be invoked using show() method. Unlike modal dialogs, they still allow interaction with the surrounding content. An example use-case may be a find-in-page dialog for a document editor, where you still want to allow the user to interact with the rest of the document.

Using Forms with <dialog>

Forms within dialogs can be used to request information from the user, such as when a shipping address or payment details are needed.

Unlike a traditional <form>, where method="get" or "post" indicates that the form data is sent to a server, using <form method="dialog"> causes form submission instead to close the dialog and set the returnValue property to the submit button’s value. This can save you from writing custom code, while providing the correct semantics to your web page.

We can simplify the initial example using this new feature:

<dialog id="confirmation-dialog">
    <form method="dialog">
        <h1>Do you want to delete everything?</h1>
        <p>You will lose all your data.</p>
        <button type="submit" value="Canceled!">Cancel</button>
        <button type="submit" value="Deleted!">Delete!</button>
    </form>
</dialog>

<button id="delete">Delete everything</button>
<p id="result"></p>

<script>
let dialog = document.getElementById("confirmation-dialog");

document.getElementById("delete").addEventListener("click", function() {
    dialog.showModal();
});

dialog.addEventListener("close", function() {
    document.getElementById("result").textContent = dialog.returnValue;
});
</script>

Note the use of the close event here, which is special to <dialog>.

Example confirmation dialog with a form

Styling

The semi-transparent box behind the dialog that you may have noticed from previous examples is the ::backdrop pseudo-element. By default, it is styled so it covers the whole viewport. Like the dialog itself, you can style the backdrop using CSS. Animations can also be used if you would like to add a fade-in effect for instance.

Note that the backdrop is only shown for modal dialogs.

Here is an example:

<dialog>
    <h1>This is a pretty dialog</h1>
    <p>The backdrop animates!</p>
</dialog>

<button onclick="document.querySelector('dialog').showModal()">Show the dialog</button>

<style>
dialog {
    box-shadow: 0 2px 5px rgba(0,0,0,0.3);
    border: none;
    border-radius: 10px;
}

dialog::backdrop {
    background: linear-gradient(rgba(0,0,0,0.1), rgba(0,0,0,0.4));
    animation: fade-in 1s;
}

@keyframes fade-in {
    from {
        opacity: 0;
    }
    to {
        opacity: 1;
    }
}
</style>

This is a pretty dialog

The backdrop animates!

Pretty dialog example styled and animated

Accessibility

For accessibility tools, the <dialog> element is equivalent to role="dialog". In addition to that, a modal dialog will behave similarly to an element with aria-modal="true".

Users can dismiss modal dialogs using the “Escape” key on desktop browsers. That will trigger a cancel event which you can intercept. If multiple modal dialogs are opened, the one shown last will be dismissed.

It is also possible to specify an element to initially focus on when opening dialogs by adding the autofocus attribute to the relevant element.

Browser Support

Next Steps

In this post, we’ve covered the basics of <dialog> and the features around it. Here are the next steps around this element:

We are working on getting the element interoperable with other browser vendors as part of the Interop 2022 effort. One of the main discussions is around initial focus behaviour, to agree on which elements should be focused by default when there is no element with the autofocus attribute.

As part of implementing <dialog> we’ve also made advances on the inert attribute to get interoperable behavior across browsers. It is currently disabled by default and not yet standardized, but you can enable the “inert attribute” in the Experimental Features menu from the Develop menu in Safari Technology Preview to test it.

Feel free to reach out to @therealntim on Twitter for any questions. To report any issues, please file a bug blocking bug 84635.