Skip to content

Accessibility

Modal dialogs are one of the easiest components to get wrong. NXPopup is built on the native HTML <dialog> element specifically because the browser then handles the hardest parts correctly.

What the native dialog provides

Opening with showModal() gives the following behaviour from the browser itself, rather than from hand-written JavaScript:

  • Focus containment. Tab and Shift+Tab cycle within the dialog and cannot reach the page behind it.
  • Inert background. Content outside the dialog is not reachable by keyboard, pointer, or assistive technology.
  • Escape to close. Handled natively; NXPopup intercepts it only to run the closing animation.
  • Top-layer rendering. The dialog is painted above all page content regardless of z-index.

Keyboard behaviour

KeyResult
Tab / Shift+TabCycles through the close button and CTA, staying inside the dialog.
EscapeCloses the popup, with the exit animation.
Enter / SpaceActivates the focused control.

Focus on open

Focus moves to the popup frame, which is a non-interactive container with tabindex="-1". This is deliberate:

  • The dialog is announced to screen readers.
  • No button is pre-armed, so an immediate Enter press cannot accidentally follow the CTA.
  • The first Tab press moves to the close button and shows a visible focus ring, as normal.

Focus on close

Focus returns to whatever the visitor was on before the popup opened, so keyboard and screen-reader users are not dropped back at the top of the page.

Screen reader labelling

The dialog is labelled from the popup's own content:

  • With a title, aria-labelledby points at the heading.
  • With no title, a translated aria-label is used instead, so the dialog always has an accessible name.
  • With body content, aria-describedby points at it. With no body, the attribute is omitted rather than left dangling.

The close button carries a translated aria-label, and its icon is marked aria-hidden.

Reduced motion

When a visitor has prefers-reduced-motion: reduce set, the open and close transitions are disabled and the popup appears and disappears immediately. The script skips waiting for a transition in that case, so closing stays instant.

Writing accessible popup content

The module handles the mechanics; the content is yours:

  • Give every popup a title. It becomes the dialog's accessible name.
  • Write a descriptive CTA. "Learn More" is acceptable in context; "Click here" is not.
  • Check colour contrast. The colour settings let you choose anything, including combinations that fail WCAG AA. The default palette places white text on a dark image; if you change the background, verify the title, body, and button text still meet 4.5:1.
  • Do not rely on the popup alone. Anything essential should also exist on the page, since visitors can dismiss the popup.

Choosing considerate triggers

Accessibility includes not being hostile:

  • Avoid a 0ms delay on content pages — it interrupts before the visitor has oriented.
  • Use the page-view gate so first-time visitors are not immediately interrupted.
  • Keep Dismiss on Backdrop Click off (the default) so an accidental click is not treated as a decision.
  • Set a realistic Dismissal Period. Re-prompting a visitor who said no is the most common complaint about popups.

Standards notes

The implementation targets WCAG 2.1 AA for the component itself, including 2.1.2 No Keyboard Trap (via the native dialog's managed focus), 2.4.3 Focus Order, and 2.4.7 Focus Visible.

Two criteria depend on your configuration rather than the module: 1.4.3 Contrast is determined by the colours you choose, and 2.2.1 Timing Adjustable by whether your popup contains time-limited content. NXPopup never auto-closes, so the visitor always controls dismissal.