#5045·nextra

a11y: theme-switcher button has no accessible name; callout code/links fail 4.5:1 contrast

Author: ericzikoCreated Aug 21, 2026Updated Aug 21, 2026

Summary

Two WCAG 2.1 AA issues in [email protected], both in theme-owned markup rather than author content. Measured with axe-core 4.13.0 against a production build.

1. Theme-switcher button has no accessible name (button-name, critical)

The headless-ui listbox button in the sidebar renders with no text, aria-label, aria-labelledby, or title:

xml
<button class="x:cursor-pointer x:h-7 x:rounded-md x:px-2 x:text-xs x:font-medium ..."
        id="headlessui-listbox-button-...">

axe reports:

button-name [critical] — Buttons must have discernible text
  Element does not have inner text that is visible to screen readers
  aria-label attribute does not exist or is empty
  aria-labelledby attribute does not exist, references elements that do not exist or is empty
  Element has no title attribute

It appears once per page, so on a 50-page site that is 50 critical violations. A screen reader user gets an unlabelled button with no indication it controls the colour theme.

Suggested fix: an aria-label on the listbox button (e.g. "Change theme"), ideally routed through the existing i18n strings.

2. Inline code and links inside a <Callout> fall below 4.5:1 (color-contrast, serious)

All measured on the theme's own default palette, light mode, normal weight, 14.4px/16px:

Element Foreground Background Ratio Needs
code in a Callout #9810fa #ece1f7 4.40 4.5
code inside a link #006be6 #f3f3f3 4.46 4.5
link inside an info Callout #006be6 #dbeafe 4.05 4.5
link on a #f3f4f6 surface #006be6 #f3f4f6 4.49 4.5

On a docs site that uses callouts with inline code — which the Nextra docs themselves recommend — this produced 61 serious violations across 10 sampled pages.

Three of the four miss by less than 0.5, and one by 0.01, so this reads as the palette never having been contrast-checked against the tinted callout backgrounds specifically rather than a deliberate trade-off.

Suggested fix: darken --nextra-primary-* for light mode, or give .nextra-callout its own code/link colours. For reference, values that clear 4.5:1 on every callout tint plus the page, tab-strip and code-chip surfaces:

  • code in callout: #7e22ce (5.55 on #ece1f7)
  • links generally: #005fcc (4.75 worst case across all surfaces)
  • links in callouts: #0052b3 (5.84–6.84 across the four tints)

Reproduction

bash
npx create-next-app -e https://github.com/shuding/nextra/tree/main/examples/docs
# add a page with a <Callout type="info"> containing inline `code` and a link
npm run build && npm start
npx @axe-core/cli http://localhost:3000/ --tags wcag2a,wcag2aa,wcag21a,wcag21aa

Found while building a 50-page docs site on Nextra 4.6.1. I worked around #2 with a CSS override, but #1 cannot be fixed from user land since the button is theme-internal. Happy to open a PR for either.