How-To - NXPopup

How to Make a Joomla Popup That's Accessible (and Doesn't Fail an Audit)

  • Platform: Joomla
  • Edition required: Free
  • Difficulty: Beginner
  • Time needed: About 45 minutes
  • You will need: Joomla 5 or 6 with the NXPopup module installed A screen reader for testing - NVDA on Windows or VoiceOver on macOS, both free A contrast checker
  • Reference documentation: https://docs.nexusplugins.com/products/nxpopup/accessibility

Popups are one of the most reliable ways to fail an accessibility audit. The usual findings are always the same: keyboard users get trapped, screen readers never hear the thing open, and the close button is invisible or too small.

NXPopup handles that layer for you. What it can't do is stop you choosing grey text on a white background. This guide covers what's already handled and what's still your job.

The NXPopup dialog open on a site frontend with a visible keyboard focus ring on the close button.
Image 1. The popup open on the frontend with a visible focus ring on the close button.

What's already handled

The module builds on the browser's native <dialog> element opened with showModal(), which means the hard parts come from the browser rather than from script that might not fire.

Behavior Why it matters
Focus is trapped inside while open Keyboard users can't tab into the page behind
Escape always closes it No keyboard trap, whatever your settings say
Focus returns to whatever opened it The visitor doesn't lose their place
The dialog has an accessible name Screen readers announce it rather than reading a blank box
Close button is 32 by 32 pixels Above the 24 pixel minimum in WCAG 2.2
Close button is labeled Close The icon is hidden from assistive tech, so only the label is read
Focus rings on close and CTA Visible keyboard focus, with an offset so it's not lost against the edge
Reduced motion is respected Animation is skipped for visitors who ask for that

Two details worth knowing because they look like bugs and aren't.

Nothing is focused when the popup opens. showModal() would normally focus the first control, painting a focus ring on the close button the moment it appears. Instead focus goes to the popup frame itself. The dialog is still announced, no button is pre-armed, and the first Tab press behaves normally.

Escape closes the popup even with Dismiss on Escape Key turned off. That setting only controls whether the dismissal is remembered, not whether Escape works. Escape closing is never optional.


Step 1: Give it a real title

In the module settings, open the Content tab and fill in Popup Title.

The title becomes the dialog's accessible name, so a screen reader announces your actual heading. Without one, the popup falls back to a generic Notification, which passes a name check but tells the visitor nothing.

Write a title that makes sense with no other context, since that's exactly how it'll be heard: 10% off your first order rather than Special offer!.


Step 2: Check your color contrast

This is the setting most likely to fail an audit, and the module can't check it for you.

Under Appearance and CTA Button you can set Background Color, Title Highlight Color, Button Background Color, Button Text Color, and Button Border Color. Every one of them is free to produce something unreadable.

The thresholds you need:

Element Minimum ratio
Body text4.5 to 1 against its background
Large text, roughly 24px or 19px bold and above3 to 1
Button borders and other UI boundaries3 to 1

Paste your chosen colors into any contrast checker before you save. Pale grey on white and white on light brand colors are the two that catch people out.

If you set a Background Image, check the text against the busiest part of the image, not the average.

The Appearance tab of the NXPopup module showing the background and title highlight color pickers.
Image 2. The Appearance tab with the color settings.

Step 3: Write a CTA that stands alone

Under CTA Button, Button Text is read out on its own when a screen reader user browses by links or buttons. Click here and Read more are useless in that list.

Use the destination as the label: Browse the sale, Book a demo, Download the guide.

If you set Button Target to open a new tab, say so in the text or accept that the visitor gets a surprise. NXPopup adds rel="noopener noreferrer" automatically, which is the security half, but the warning is on you.


Step 4: Leave motion alone

The popup animates in and out, and skips that animation entirely for visitors whose system asks for reduced motion. Both the styling and the closing logic check for it, so there's no half-animated state.

You don't need to configure anything. Just avoid adding your own animation on top through custom CSS, because that layer won't check the preference.


Step 5: Test it with a keyboard

Five minutes, no tools needed. Open the page and put the mouse away.

  1. Wait for the popup to open. Press Tab. A visible ring should appear on the first control.
  2. Keep tabbing. Focus should cycle inside the popup and never reach the page behind it.
  3. Press Escape. The popup should close.
  4. Look at where focus went. It should be back on whatever you were on before, not at the top of the page.
  5. Reopen and close it with the close button instead. Same result.

If steps 2 to 4 pass, you've cleared the findings that sink most popups.


Step 6: Test it with a screen reader

Use whatever is on your machine. VoiceOver on macOS with Cmd+F5, or NVDA on Windows, which is free.

Trigger the popup and listen. You should hear it announced as a dialog, with your title as its name, followed by the content. Then check that the close button is announced as Close and not as button or a filename.

That's the whole test. If your title is announced, you're in good shape.

The Content tab of the NXPopup module with the popup title and content filled in.
Image 3. The Content tab with the popup title and content filled in.

Being reasonable about interruption

Accessibility isn't only what a checker measures.

Under Display Behaviour, Open Trigger offers After a delay, After scrolling, and On exit intent. Under Dismissal, Dismissal Period (days) controls how long a dismissal is remembered.

Some judgment calls that keep people on your side:

  • Give visitors a moment before interrupting. Opening instantly, before the page has settled, is disorienting for everyone and worse for someone using a screen reader.
  • Respect a dismissal for a real length of time. A popup that returns on the next page view reads as broken.
  • Use Show After N Page Views so first-time visitors get to see your site before being asked for anything.

The popup never closes itself on a timer, which is deliberate. A dialog that vanishes while someone is still reading it is its own accessibility problem.


If an audit flags something

"Dialog has no accessible name."
Popup Title is empty and something is interfering with the fallback label. Set a title.
"Insufficient color contrast."
Almost always the CTA button or title highlight. See Step 2.
"Content is not announced."
The popup has a title but no content, so there's nothing for the description to point at. That's expected for a title-only popup and is not a real failure.
"Focus is not visible."
Something in your template's CSS is overriding the focus ring. Search your template for outline: none and remove it.
"Target size too small."
Not the close button, which is 32 pixels. Check links inside your popup content.
"Images missing alt text."
Content you pasted in. The popup body is your HTML, so alt attributes are yours to add.

More on this

Full documentation: NXPopup.