Skip to content
easeweb
Search topics

Pop-ups that can't be closed with a keyboard

A sign-up pop-up keeps Tab inside it, ignores Escape and draws its × as a span, so keyboard users can't close it without signing up.

WCAG 2.2
SC 2.1.2A
Required by
Section 508 · EN 301 549 (EU)
Broken <span class="popup-close">×</span>
The accessibility problem illustrated: Motor:How do I close this?
01

The problem

Keyboard users can't close the sign-up pop-up, so they can't reach the page behind it without signing up.

02

Try it

Tab into the shop’s page, then close the pop-up that opens, with the keyboard alone.

Try Tab, Shift + Tab and Escape: does focus ever reach the ×?

Apply a fix and try again, and see where focus is once the pop-up has closed.

Broken Can you fix this?

BrokenA pop-up whose × Tab never reaches

Juniper Ceramics

New this week

Speckled stoneware, thrown by hand and glazed in small batches.

A recreated demo. The broken version is intentionally inaccessible.

03

The fix

Make the × a named button, and close the pop-up on Escape, with showModal() or with a key handler.

  1. 1A pop-up that holds focus closes on Escape.
  2. 2Its close control is a button with a name, and Tab reaches it.
  3. 3Closing it puts focus back where the person was.
Before A pop-up whose × Tab never reaches
<div class="popup-overlay" hidden>  <div class="popup" role="dialog" aria-modal="true" aria-labelledby="popup-title">    <span class="popup-close">×</span>    <h2 id="popup-title">Get 10% off your first order</h2>    <p>Sign up for news of new pieces and sales.</p>    <form class="popup-form">      <label for="popup-email">Email address</label>      <input id="popup-email" name="email" type="email" autocomplete="email" required>      <button>Sign up</button>    </form>  </div></div>
After

A native dialog

<dialog class="popup" aria-labelledby="popup-title">  <button type="button" class="popup-close" aria-label="Close">×</button>  <h2 id="popup-title">Get 10% off your first order</h2>  <p>Sign up for news of new pieces and sales.</p>  <form class="popup-form">    <label for="popup-email">Email address</label>    <input id="popup-email" name="email" type="email" autocomplete="email" required>    <button>Sign up</button>  </form></dialog>

Why this fix: Use native HTML first

Easily confused
04

Verify the fix

5 checks, no mouse.

Test with: Keyboard, Screen reader

0 of 5 checked

Record the OS, browser and assistive-technology versions, the build, the date, and the actual result of each step. Repeat after the pop-up, the tool that shows it, or its settings change.

How screen readers handle <dialog>

Limits

This is a starting pattern for one pop-up, not a guarantee for every overlay. The snippets leave out the part that remembers a visitor has closed the pop-up, so it doesn't open on every page, and what subscribe() does with the address. Where a closed pop-up should send focus when nothing had focus before it opened depends on the page; leaving it to the browser is a reasonable default, but where Tab carries on from then differs between browsers, so check it in the ones you support. Test the complete journey with the assistive technology your visitors use.

This is a recreated teaching example, not a finding about a named client. The code is a starting pattern: test it in your own product. No completed assistive-technology test is claimed here.

EaseWeb service

Fixed it? Keep it from coming back.

I turn guides like this one into rules your coding agents follow and checks your CI runs. Then I retest by hand with a keyboard and screen readers, periodically.

See the service