Monday, March 2, 2026

Popover API or Dialog API: Which to Select?


Selecting between Popover API and Dialog API is tough as a result of they appear to do the identical job, however they don’t!

After a bit a lot of analysis, I found that the Popover API and Dialog API are wildly completely different by way of accessibility. So, in the event you’re making an attempt to resolve whether or not to make use of Popover API or Dialog’s API, I like to recommend you:

  • Use Popover API for many popovers.
  • Use Dialog’s API just for modal dialogs.

Popovers vs. Dialogs

The connection between Popovers and Dialogs are complicated to most builders, nevertheless it’s really fairly easy.

Dialogs are merely subsets of popovers. And modal dialogs are subsets of dialogs. Learn this text if you wish to perceive the rationale behind this relationship.

![[popover-accessible-roles.jpg.webp]]

For this reason you could possibly use the Popover API even on a

ingredient.

 
...

Stylistically, the distinction between popovers and modals are even clearer:

  • Modals ought to present a backdrop.
  • Popovers mustn’t.

Subsequently, you need to by no means type a popover’s ::backdrop ingredient. Doing so will merely point out that the popover is a dialog — which creates an entire can of issues.

It is best to solely type a modal’s ::backdrop ingredient.

Popover API and its accessibility

Constructing a popover with the Popover API is comparatively straightforward. You specify three issues:

  • a popovertarget attribute on the popover set off,
  • an id on the popover, and
  • a popover attribute on the popover.

The popovertarget should match the id.


 The Popover Content material 

Discover that I’m utilizing the

ingredient to create a dialog position. That is non-obligatory, however really useful. I do that as a result of dialog is a nice default position since most popovers are merely simply dialogs.

This two strains of code comes with a ton of accessibility options already built-in for you:

  • Automated focus administration
    • Focus goes to the popover when opening.
    • Focus goes again to the set off when closing.
  • Automated aria connection
    • No want to write down aria-expanded, aria-popup and aria-controls. Browsers deal with these natively. Woo!
  • Automated mild dismiss
    • Popover closes when person clicks exterior.
    • Popover closes after they press the Esc key.

Now, with out further styling, the popover appears to be like kinda meh. Styling is an entire ‘nother challenge, so we’ll sort out that in a future article. Geoff has a number of notes you possibly can overview within the meantime.

Dialog API and its accessibility

In contrast to the Popover API, the Dialog API doesn’t have many built-in options by default:

  • No computerized focus administration
  • No computerized ARIA connection
  • No computerized mild dismiss

So, we’ve to construct them ourselves with JavaScript. For this reason the Popover API is superior to the Dialog API in nearly each side — apart from one: when modals are concerned.

The Dialog API has a showModal technique. When showModal is used, the Dialog API creates a modal. It:

  1. mechanically inerts different components,
  2. prevents customers from tabbing into different components, and
  3. prevents display screen readers from reaching different components.

It does this so successfully, we now not must lure focus inside the modal.

However we gotta maintain the main target and ARIA stuff once we use the Dialog API, so let’s sort out the naked minimal code you want for a functioning dialog.

We’ll start by constructing the HTML scaffold:



The Popover Content material

Discover I didn’t add any aria-expanded within the HTML. I do that for a wide range of causes:

  1. This reduces the complexity of the HTML.
  2. We will write aria-expanded, aria-controls, and the main target stuff instantly in JavaScript – since these received’t work with out JavaScript.
  3. Doing so makes this HTML very reusable.

Organising

I’m going to write down a couple of vanilla JavaScript implementation right here. In case you’re utilizing a framework, like React or Svelte, you’ll have to make a few adjustments — however I hope that it’s gonna be simple for you.

Very first thing to do is to loop via all dialog-invokers and set aria-expanded to false. This creates the preliminary state.

We may even set aria-controls to the

ingredient. We’ll do that despite the fact that aria-controls is poop, ’trigger there’s no higher technique to join these components (and there’s no hurt connecting them) so far as I do know.

const modalInvokers = Array.from(doc.querySelectorAll('.modal-invoker'))

modalInvokers.forEach(invoker => {
  const dialogId = invoker.dataset.goal
  const dialog = doc.querySelector(`#${dialogId}`)
  invoker.setAttribute('aria-expanded', false)
  invoker.setAttribute('aria-controls', dialogId)
})

Opening the modal

When the invoker/set off is clicked, we gotta:

  1. change the aria-expanded from false to true to present the modal to assistive tech customers, and
  2. use the showModal perform to open the modal.

We don’t have to write down any code to cover the modal on this click on handler as a result of customers won’t ever get to click on on the invoker when the dialog is opened.

modalInvokers.forEach(invoker => {
  // ... 

  // Opens the modal
  invoker.addEventListener('click on', occasion => {
    invoker.setAttribute('aria-expanded', true)
    dialog.showModal()
  })
})

Nice. The modal is open. Now we gotta write code to shut the modal.

Closing the modal

By default, showModal doesn’t have computerized mild dismiss, so customers can’t shut the modal by clicking on the overlay, or by hitting the Esc key. This implies we’ve so as to add one other button that closes the modal. This have to be positioned inside the modal content material.

 
  
  

When customers click on the shut button, we’ve to:

  1. set aria-expanded on the opening invoker to false,
  2. shut the modal with the shut technique, and
  3. convey focus again to the opening invoker ingredient.
modalInvokers.forEach(invoker => {
  // ... 

  // Opens the modal
  invoker.addEventListener('click on', occasion => {
    invoker.setAttribute('aria-expanded', true)
    dialog.showModal()
  })
})

const modalClosers = Array.from(doc.querySelectorAll('.modal-closer'))

modalClosers.forEach(nearer => {
  const dialog = nearer.closest('dialog')
  const dialogId = dialog.id
  const invoker = doc.querySelector(`[data-target="${dialogId}"]`)
  
  nearer.addEventListener('click on', occasion => {
    dialog.shut()
    invoker.setAttribute('aria-expanded', false)
    invoker.focus()
  })
})

Phew, with this, we’re accomplished with the primary implementation.

In fact, there’s superior work like mild dismiss and styling… which we are able to sort out in a future article.

Can you employ the Popover API to create modals?

Yeah, you possibly can.

However you’ll have to deal with these by yourself:

  1. Inerting different components
  2. Trapping focus

I feel what we did earlier (setting aria-expanded, aria-controls, and focus) are simpler in comparison with inerting components and trapping focus.

The Dialog API would possibly turn out to be a lot simpler to make use of sooner or later

A proposal about invoker instructions has been created in order that the Dialog API can embrace popovertarget just like the Popover API.

That is on the best way, so we’d be capable to make modals even less complicated with the Dialog API sooner or later. Within the meantime, we gotta do the mandatory work to patch accessibility stuff.

Deep dive into constructing workable popovers and modals

We’ve solely started to scratch the floor of constructing working popovers and modals with the code above — they’re barebone variations which are accessible, however they undoubtedly don’t look good and might’t be used for skilled functions but.

To make the method of constructing popovers and modals simpler, we are going to dive deeper into the implementation particulars for a professional-grade popover and a professional-grade modal in future articles.

Within the meantime, I hope these offer you some concepts on when to decide on the Popover API and the Dialog API!

Bear in mind, there’s no want to make use of each. One will do.

Related Articles

Latest Articles