Clarifying the Relationship Between Popovers and Dialogs

Featured Imgs 23

The difference between Popovers (i.e., the popover attribute) and Dialogs (i.e., both the <dialog> element and the dialog accessible role) is incredibly confusing — so much that many articles (like this, this, and this) have tried to shed some light on the issue.

If you’re still feeling confused, I hope this one clears up that confusion once and for all.

Distinguishing Popovers From Dialogs

Let’s pull back on the technical implementations and consider the greater picture that makes more sense and puts everything into perspective.

Line diagram connecting the popover attribute to six types of accessible roles, including dialog.

The reason for this categorization comes from a couple of noteworthy points.

First, we know that a popover is content that “pops” up when a user clicks a button (or hovers over it, or focuses on it). In the ARIA world, there is a useful attribute called aria-haspopup that categorizes such popups into five different roles:

  • menu
  • listbox
  • tree
  • grid
  • dialog

Strictly speaking, there’s a sixth value, true, that evaluates to menu. I didn’t include it above since it’s effectively just menu.

By virtue of dialog being on this list, we already know that dialog is a type of popover. But there’s more evidence behind this too.

The Three Types of Dialogues

Since we’re already talking about the dialog role, let’s further expand that into its subcategories:

Lone diagram connecting the popover attribute to six accessible roles, including dialog, which is broken out into three categories.

Dialogs can be categorized into three main kinds:

  • Modal: A dialog with an overlay and focus trapping
  • Non-Modal: A dialog with neither an overlay nor focus trapping
  • Alert Dialog: A dialog that alerts screen readers when shown. It can be either modal or non-modal.

This brings us to another reason why a dialog is considered a popover.

Some people may say that popovers are strictly non-modal, but this seems to be a major misunderstanding — because popovers have a ::backdrop pseudo-element on the top layer. The presence of ::backdrop indicates that popovers are modal. Quoting the CSS-Tricks almanac:

The ::backdrop CSS pseudo-element creates a backdrop that covers the entire viewport and is rendered immediately below a <dialog>, an element with the popup attribute, or any element that enters fullscreen mode using the Fullscreen API.

That said, I don’t recommend using the Popover API for modality because it doesn’t have a showModal() method (that <dialog> has) that creates inertness, focus trapping, and other necessary features to make it a real modal. If you only use the Popover API, you’ll need to build those features from scratch.

So, the fact that popovers can be modal means that a dialog is simply one kind of popover.

A Popover Needs an Accessible Role

Popovers need a role to be accessible. Hidde has a great article on selecting the right role, but I’m going to provide some points in this article as well.

To start, you can use one of the aria-haspopup roles mentioned above:

  • menu
  • listbox
  • tree
  • grid
  • dialog

You could also use one of the more complex roles like:

  • treegrid
  • alertdialog

There are two additional roles that are slightly more contentious but may do just fine.

  • tooltip
  • status

To understand why tooltip and status could be valid popover roles, we need to take a detour into the world of tooltips.

A Note on Tooltips

From a visual perspective, a tooltip is a popover because it contains a tiny window that pops up when the tooltip is displayed.

I included tooltip in the mental model because it is reasonable to implement tooltip with the Popover API.

<div popver role="tooltip">...</div>

The tooltip role doesn’t do much in screen readers today so you need to use aria-describedby to create accessible tooltips. But it is still important because it may extend accessibility support for some software.

But, from an accessibility standpoint, tooltips are not popovers. In the accessibility world, tooltips must not contain interactive content. If they contain interactive content, you’re not looking at a tooltip, but a dialog.

You’re thinking of dialogs. Use a dialog.

Heydon Pickering, “Your Tooltips are Bogus”

This is also why aria-haspopup doesn’t include tooltiparia-haspopup is supposed to signify interactive content but a tooltip must not contain interactive content.

With that, let’s move on to status which is an interesting role that requires some explanation.

Why status?

Tooltips have a pretty complex history in the world of accessible interfaces so there’s a lot of discussion and contention over it.

To keep things short (again), there’s an accessibility issue with tooltips since tooltips should only show on hover. This means screen readers and mobile phone users won’t be able to see those tooltips (since they can’t hover on the interface).

Steve Faulkner created an alternative — toggletips — to fill the gap. In doing so, he explained that toggletip content must be announced by screen readers through live regions.

When initially displayed content is announced by (most) screen readers that support aria-live

Heydon Pickering later added that status can be used in his article on toggletips.

We can supply an empty live region, and populate it with the toggletip “bubble” when it is invoked. This will both make the bubble appear visually and cause the live region to announce the tooltip’s information.

<!-- Code example by Heydon -->
<span class="tooltip-container"> 
  <button type="button" aria-label="more info" data-toggletip-content="This clarifies whatever needs clarifying">i</button> 
  <span role="status"> 
    <span class="toggletip-bubble">This clarifies whatever needs clarifying</span> 
  </span>
</span>

This is why status can be a potential role for a popover, but you must use discretion when creating it.

That said, I’ve chosen not to include the status role in the Popover mental model because status is a live region role and hence different from the rest.

In Summary

Here’s a quick summary of the mental model:

  • Popover is an umbrella term for any kind of on-demand popup.
  • Dialog is one type of popover — a kind that creates a new window (or card) to contain some content.

When you internalize this, it’s not hard to see why the Popover API can be used with the dialog element.

<!-- Uses the popover API. Role needs to be determined manually -->
<div popover>...</div>

<!-- Dialog with the popover API. Role is dialog -->
<dialog popover>...</dialog>

<!-- Dialog that doesn't use the popover API. Role is dialog -->
<dialog>...</dialog>

When choosing a role for your popover, you can use one of these roles safely.

  • menu
  • listbox
  • tree
  • grid
  • treegrid
  • dialog
  • alertdialog

The added benefit is most of these roles work together with aria-haspopup which gained decent support in screen readers last year.

Of course, there are a couple more you can use like status and tooltip, but you won’t be able to use them together with aria-haspopup.

Further Reading


Clarifying the Relationship Between Popovers and Dialogs originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

Solving Background Overflow With Inherited Border Radii

Featured Imgs 23

One of the interesting (but annoying) things about CSS is the background of children’s elements can bleed out of the border radius of the parent element. Here’s an example of a card with an inner element. If the inner element is given a background, it can bleed out of the card’s border.

The easiest way to resolve this problem is to add overflow: hidden to the card element. I’m sure that’s the go-to solution most of us reach for when this happens.

But doing this creates a new problem — content outside the card element gets clipped off — so you can’t use negative margins or position: absolute to shift the children’s content out of the card.

There is a slightly more tedious — but more effective — way to prevent a child’s background from bleeding out of the parent’s border-radius. And that is to add the same border-radius to the child element.

The easiest way to do this is allowing the child to inherit the parent’s border-radius:

.child {
  border-radius: inherit;
}

If the border-radius shorthand is too much, you can still inherit the radius for each of the four corners on a case-by-case basis:

.child {
  border-top-left-radius: inherit;
  border-top-right-radius: inherit;
  border-bottom-left-radius: inherit;
  border-bottom-right-radius: inherit;
}

Or, for those of you who’re willing to use logical properties, here’s the equivalent. (For an easier way to understand logical properties, replace top and left with start, and bottom and right with end.)

.child {
  border-start-start-radius: inherit;
  border-top-end-radius: inherit;
  border-end-start-radius: inherit;
  border-end-end-radius: inherit;
}

Can’t we just apply a background on the card?

If you have a background directly on the .card that contains the border-radius, you will achieve the same effect. So, why not?

Well, sometimes you can’t do that. One situation is when you have a .card that’s split into two, and only one part is colored in.

So, why should we do this?

Peace of mind is probably the best reason. At the very least, you know you won’t be creating problems down the road with the radius manipulation solution.

This pattern is going to be especially helpful when CSS Anchor Positioning gains full support. I expect that would become the norm popover positioning soon in about 1-2 years.

That said, for popovers, I personally prefer to move the popover content out of the document flow and into the <body> element as a direct descendant. By doing this, I prevent overflow: hidden from cutting off any of my popovers when I use anchor positioning.


Solving Background Overflow With Inherited Border Radii originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.