A better non-modal dialog with the Popover API


What’s wrong with show()?

A non-modal dialog opened via the show() method has the following limitations:

  • The dialog will not use the top layer.
  • No ::backdrop pseudo-element. Using ::backdrop for a non-modal dialog is somewhat uncommon, but so long as its kept mostly transparent, its a viable UX choice.

Without the popover API, there is no HTML-based way to open or close a non-modal dialog, whereas a popover can be opened and closed via either the popovertarget and popovertargetaction attributes or the command and commandfor attributes.

<dialog popover>: combining the popover API and the dialog element

The only one way to create a non-modal dialog that is placed in the top layer and has a ::backdrop pseudo-element is by using the popover attribute and showing the dialog via a popover API method or command.

A dialog that can be closed via light dismiss or by pressing the escape key:

<dialog popover id="dialog1">Example popover dialog</dialog>
<button popovertarget="dialog1">Show dialog</button>
Example popover dialog

A dialog without light dismiss and that is not closed via the escape key:

<dialog popover="manual" id="dialog2">
Example popover dialog
<button popovertargetaction="hide" popovertarget="dialog2">Close</button>
</dialog>

<button popovertarget="dialog2">Show dialog</button>
Example popover dialog

Does it behave more like a dialog, or more like a popover?

How a dialog/popover combo behaves depends on the method or command used to open it. If a dialog element includes the popover attribute but is opened via show() or via the open attribute, the popover attribute will have no effect. If opened via a popover API command or method, it will act like a popover in almost all respects:

  • In CSS the dialog will match :popover-open but not [open] or :open
  • The element can only be closed via a popover method or command

There aren’t many behavioural differences between <div popover> and <dialog popover>, but it is important to use the most semantically correct element: the dialog element has the advantage of an implicit ARIA role of dialog. The one notable functional difference is focus behaviour. When shown, <dialog popover> will focus the first focusable element within the dialog, or the dialog itself if no children are focusable. The is different from the usual popover focus behaviour: opening <div popover>, for example, will cause the first focusable element within the popover to be the next tab stop.

Shortcomings of <dialog popover>

The closedby attribute

One useful piece of functionality you lose by using the popover API is the closedby attribute. This attribute currently only works if a dialog is opened via show(), showModal() or the open attribute. <dialog popover="auto"> has equivalent close behaviour to closedby=any. <dialog popover="manual"> has the same close behaviour as as closedby=none. There is no popover equivalent to closedby=closerequest. If you think closedby should work for dialogs that use the popover API, please leave a 👍 or a thoughtful comment on this GitHub issue.

The open attribute

There’s no equivalent to the open attribute for the Popover API. <dialog popover open> will open the dialog, but the popover attribute will have no effect, meaning the dialog will not be in the top layer, will not have a ::backdrop pseudo-element, and can only be closed by the close method or command. In CSS it will match [open] and :open but not :popover-open. There is a GitHub issue.