With the new
popover attribute in HTML, we can put elements in the top layer and allow them to disappear with ‘light dismiss’. This attribute adds behaviour, not semantics: you're supposed to add your own when it makes sense. In this post, we'll look at different semantics that could make sense for your popover-behaved elements.
Note on support:
popover is experimental (but about to ship) in Chrome/Edge, available for experimentation in Safari Technology Preview, and considered positive by Mozilla / in development in Firefox
Elements in HTML can have semantics, meaning they are one of several predefined things, and not another. Semantics answer the question ‘what is this thing?’, out of a list of standardised things. This information is then relied upon by browsers and assistive technologies in their UIs.
On the web, semantics are implemented as an element's ‘role’ (roughly speaking). Semantics are built-in (‘implicit’) to some elements: a
h1 has the
heading role, an
a has the
link role and so forth. Roles can also be added with a
role attribute explicitly, for some roles that is the only way as there exists no corresponding element. If there's an element and a value for ‘role’, it doesn't really matter for end users which you use, but generally you don't want to overwrite implicit role. As mentioned, your user's browser or assistive technology may use the role to provide a UI (for instance, a screenreader may generate a list of links or headings, a reader mode may render list items with bullets).
Popovers have no default role
Whenever we add the
popover attribute to an element, it continues to be that element semantically, just with some specific behaviours. Menus remain menus, dialogs remain dialogs, and so on. The popover attribute does not change an element's role. It's a bit like the
contenteditable attribute in that sense. In addition to choosing that you want the popover behaviour, you need to decide if you add a role and, if so, which role.
The most basic example of a popover:
<button type="button" popovertarget="my-popover"> Toggle popover </button> <div popover id="my-popover"> ... </div>
This is how it works:
divwill be invisible on page load, because it has a
popoverattribute and popovers are closed on page load by default
divwill also be toggleable via the button, as the button points to the
div's ID in its
Potential roles for your popover
Let's now look at common roles for popovers: menu, dialog and listbox, and consider what to do about tooltips.
Let's start with menus. The
menu role is what you'd use when your component offers a list of choices to the user, specifically choices that are actions.
A menu with popover behaviour can be built with a
<button type="button" popovertarget="my-menu"> Toggle menu </button> <div role="menu" popover id="my-menu"> <button onclick="doThing()" role="menuitem" tabindex="-1" autofocus>Do thing</button> <button onclick="doAnotherThing()" role="menuitem" tabindex="-1">Do another thing</button> … </div>
autofocus), the second and after would get focused moved to them when they're the next one and an arrow key is pressed (hence
tabindex="-1": this takes the buttons out of tab order, because you make them reachable with arrow keys instead).
menu role is not to be confused with the
menu element, which has a
list role and is “a semantic alternative to
Examples of when you would use
Your CMS manages a list of authors. The user can open a
menu for each author with some actions (each action has a
You're building a word processor. The “File” menu is a menu, the options (New, Open, etc) are
See also: Marco Zehe on the
menu role and “Menu control type” in Windows Accessibility Features documentation
A dialog role is what you add when an element is like a smaller window on top of the main web page. It can block interaction with the rest of the page or leave the rest of the page as it is, either way it is somewhat separate from the page, both in purpose and visually.
<dialog> element implicitly has a
dialog role, and comes with dialog methods and behaviours (like you can run
element.showModal() to show it as a modal). You can also add the dialog role manually with
role="dialog", but then you have to add the behaviours manually too.
A dialog with popover behaviour can be built like this:
<button type="button" popovertarget="my-dialog"> Toggle dialog </button> <dialog id="my-dialog" popover> ... </dialog>
You see, there's no explicit role attribute, because the
dialog role comes with the
If not using a button with
popovertarget, you could open this dialog with script using the
showPopover() method that works on any element that is a popover (by having a
popover attribute present).
Note: because this specific popover example uses the
<dialog> element, two other methods are also available (through the HTMLDialogElement):
showModal(). They have slightly different behaviours than
showPopover() would. I recommend against using these two methods on dialogs that are popovers. In other words, if you're inclined to use them, you probably don't want the
popover attribute, as that attribute's purpose would basically be defeated by
showModal() (also, in some cases you might get a console error if you try to run
showModal() on a popover). Popover is really for non-modal dialogs; see also my post on dialogs vs popovers).
Other examples of elements that could have popover behaviour and a
dialog role are:
- teaching UI
- pickers, like for a date, multiple dates, prices
- “mega navs” and other large navigational structures that cover a lot of the page (note: these should not use
role="menu", a navigation with links is semantically different from a menu with buttons)
A dialog that allows the user to specify their travel group and amount of bicycles
A dialog that teaches what the audio player is for
A “meganav” that covers other content (note: this is a dialog, not a menu)
Listboxes / autocompletes: the
A listbox is for elements where the user gets to choose from one or more options, like a
<select>. They can exist as single select (user can select one option) or multi select (user can select multiple options).
Listboxes are often part of an autocomplete or combobox widget, they are the part that contains the actual options. Like in this example:
Select menus also use listboxes to allow users to pick an option from a list
For instance, in the following example, there is a component that pops over the page's content. It contains filter and sorting buttons, as well as a listbox with actual options. The element with
popover is probably a dialog (and you could give it a
dialog role), while the element that contains options would need a role of
A listbox as part of a combobox
tooltip (with caveats) or
In their simplest form, tooltips are like the
title element in HTML, that browers display on hover. These browser built-in tooltips are problematic in many ways, including that in most browsers, there is no way to get to the contents of
title with just a keyboard. Let's call them “plain text tooltips”. They are often customised by developers, for instance to change their visual styles (currently from scratch, maybe via CSS in the future).
Plain text tooltips that display on hover or focus of a triggering element, which they describe
Sometimes they are also found underneath input fields, to explain what that input does or what is expected, like some of Scott O'Hara's custom tooltips examples.
These custom “plain text tooltips” are what the
tooltip role seems to be meant for. Note that
role="tooltip" doesn't do much in terms of screen reader announcements as Sarah Higley explains in Tooltips in the time of WCAG 2.1, though there are cases where ARIA-provided labels and descriptions don't work across browsers and assistive technologies without the role (if they aren't interactive,
img elements and also don't have a landmark or widget role). What is useful for accessibility of that kind of tooltip, going beyond roles for a moment: use
aria-describedby to link up a tooltip that describes a thing with that thing, and never place essential content in them. Also ensure that the tooltip (1) stays visible when its content is hovered, (2) is dismissable (with Escape) and (3) persists until hover/focus removed, dismissed or irrelevant (all required to meet WCAG 1.4.13).
My advice would be that whenever tooltips contain more than just plain text, a non-modal
dialog would be more appropriate (even if elements with
tooltip role were apparently meant to also allow for interactive elements). Non-modal dialog tooltips could contain semantic elements (like a heading) or interactive elements (like a link or a button). In most cases it would be best to display them on click instead of hover + focus, in which case they are really “toggletips”. Of course, if there is interactive content, that also means you'll want to consider focus order.
In this post, we've covered some of the most common semantics you could choose to use with the
listbox, plus looked at using
tooltip for plain text tooltips or
dialog for tooltips that contain anything more than plain text. Are you building components that don't really fall into any of these categories? I'm curious to learn more, slide in my DMs or email!
List of updates
- 17 May 2023: Explained attributes in menu example
- 16 May 2023: Changed example that used <menu> to use role=menu
Comments, likes & shares (62)
Kevin Bauer, Taiyo Totsuka, Ryan Trimble, John Kemp-Cruz, Steven Bassett, Reimar, Ryan DeBeasi, Elly Loel ✨🌱, Chris Burnell, Apple Annie :prami:, Ryan Randall :OpenAccess: :hc:, David Díaz, Adam Stoddard, derek :prami:, Mike-麥-Mai.html 😎, Thomas Beduneau, Vincent Valentin, meduz', Jon, Markus Günther, Kai, maddesigns, Jeff, Martín Baldassarre, Tyler Sticka, Lars Laade, Michelle Barker, Léonie Watson, Jw, Pratik Patel, Jeffrey Yasskin and Timo Tijhof liked this
handlerug, Taiyo Totsuka, Steve Faulkner, keithamus, Eric Eggert, Ryan Trimble, Ben Myers 🦖, Steven Bassett, vidak, Adrian Cochrane, Elly Loel ✨🌱, Fronteers, Apple Annie :prami:, Mike-麥-Mai.html 😎, Thomas Beduneau, Florian Schroiff, Jon, Lene Saile, Thomas Steiner :chrome:, Markus Günther, Bhupesh Singh, Tyler Sticka, Léonie Watson, Pratik Patel, Gustav Hansen, aris and Jeroen Zwartepoorte reposted this