Most popup bugs are invisible to the team that built them. You open the overlay with a mouse, the design matches the brand guide, and you ship it. Then a visitor who navigates with a keyboard finds the close button unreachable.
Those visitors are not a separate, smaller audience. Keyboard and screen reader users, people with low vision or motor impairments, and anyone tired or distracted on a phone all need the same things: contrast they can read, a close control they can hit, and a dialog that behaves predictably.
This is the accessibility pass to run on every popup before it goes live, and the QA checklist to run before launch.
Why is an inaccessible popup a conversion problem too?
Every accessibility defect has a business twin. A 12 pixel grey x is hard to see with low vision and hard to hit on a phone, so people close the tab instead of the popup. A dialog with no focus management lets keyboard users tab into the page behind it and lose their place. Both show up as a lower submit rate on the form you spent a month optimising.
How do you manage focus when a dialog opens and closes?
Focus management is what popups get wrong most often. When the dialog opens, move focus into it: the first interactive element, or the dialog itself with tabindex="-1" so a screen reader reads the heading. Then trap focus, so Tab from the last control returns to the first and Shift+Tab wraps backwards.
When the dialog closes, return focus to the trigger. Without that step a keyboard user lands at the top of the document, lost. A non modal banner, such as a cookie notice, should not trap focus at all.
What should Escape and the close button do?
Escape closes the dialog, always, including when focus sits inside a text input, and focus goes back to the trigger. A popup that ignores Escape reads as broken to everyone.
The close button should be a real button element, not a clickable div, with an accessible name of "Close". Make it at least 44 by 44 pixels, high contrast, and put it in the top corner of the card. Never make the backdrop the only way out, keep body text at 4.5 to 1 contrast or better, and never autoplay audio or video inside the overlay.
How do you label a dialog so a screen reader announces it?
A popup without a role is just a floating div. Give the container role="dialog", or role="alertdialog" for a destructive confirmation, add aria-modal="true", and point aria-labelledby at the heading inside it. Keep every id unique, or the label points at the wrong element. Announce form errors through a live region so they are heard, not only seen.
Why does an email field need a real label?
A placeholder is not a label. It disappears the moment the visitor types, it is usually low contrast, and it is not reliably announced. A visible label element tied to the field with for and id fixes all three at once, and paired with type="email" and autocomplete="email" it lets keyboards and password managers help. Show validation errors as text beside the field, not as a red border alone. It is basic form design, and it decides whether the address you collect is usable.
How do you lock scroll and treat time fairly?
Setting overflow: hidden on the body without compensating for the scrollbar width shifts the layout sideways when the popup opens. On mobile you usually need a fixed body with a saved offset to stop the page drifting behind the overlay. Restore the exact position on close, and never disable pinch zoom to hide the problem.
Timing matters too. A visitor who needs longer to read is not a slow visitor, so do not auto dismiss an offer before it can be read or open a popup the instant the page loads. Triggers and caps belong with popup timing and frequency limits.
What does the pre-launch QA checklist cover?
Run this on every new popup, on desktop and on a real phone, before it goes live.
| Check | How to test | What failure looks like |
|---|---|---|
| Keyboard path | Tab through the dialog, forward and back | Focus lands on the page behind the overlay |
| Escape | Open the dialog, press Escape from inside a field | Nothing happens, or focus is lost |
| Close button | Look at it, then tap it with a thumb | Too small, too pale, or missing |
| Focus return | Close the dialog, press Tab once | Focus jumps to the top of the page |
| Announcement | Read it with VoiceOver, NVDA or TalkBack | No dialog name, no heading, no role |
| Submit and errors | Submit empty, then submit a bad address | Error in colour only, or not announced |
| Mobile viewport | Test at 360 pixels wide, portrait and landscape | Clipped content, close button off screen |
| Slow connection | Throttle to slow 4G and reload | Layout shift, or the popup fires twice |
| Analytics | Open once, inspect the event payload | Fires on every render, not once per open |
Keep the checklist short enough that people actually run it. A popup that fails several rows converts worse than one that does not, which is why the same discipline belongs in your A/B testing routine and your mobile tap targets.
None of this is exotic: a handful of attributes, one focus trap, a close button people can see, and twenty minutes of testing with a keyboard. heycustomer.byako.dev handles the focus trap, the Escape key, the labelled dialog and the once per open event for you.
FAQ
Q: Is popup accessibility a legal requirement? A: Many jurisdictions have accessibility rules covering commercial websites, and the scope depends on where you sell. The practical answer is that the fixes are cheap and the defects cost sales either way, so treat it as product quality rather than paperwork.
Q: What is the most common popup accessibility bug? A: Missing focus management. The dialog opens, focus stays on the page behind it, and a keyboard user tabs through content they cannot see. It takes a few lines of code to fix, and almost no popup library does it by default.
Q: Should clicking the backdrop close the popup? A: Yes, it is a reasonable convenience for mouse and touch users, but never the only way out. There must be a visible close button that works with a keyboard and is announced to a screen reader.
Q: Does a bigger close button hurt conversions? A: The opposite. A close control people can find reduces hard bounces. Hiding it does not keep anyone in the popup, it pushes them out of the page.