Skip to content

Remove invalid role="menu" from the navbar collapse toggler - #14805

Open
cwickham wants to merge 3 commits into
mainfrom
fix/navbar-toggler-role
Open

Remove invalid role="menu" from the navbar collapse toggler#14805
cwickham wants to merge 3 commits into
mainfrom
fix/navbar-toggler-role

Conversation

@cwickham

@cwickham cwickham commented Aug 24, 2026

Copy link
Copy Markdown
Member

Description

Fixes #14615.

The website navbar's hamburger toggle rendered as a <button> with role="menu". That role is not valid on a button. axe-core reports it as aria-allowed-role. WAVE reports the same markup as an Error (aria_menu_broken), mapped to WCAG 2.2 SC 2.1.1 and 4.1.2, because a menu must contain at least one menuitem child. The toggle only appears when the navbar collapses at narrow viewports, so the violation only shows in mobile-width scans.

Why the role was there. #9553 (May 2024) added roles because Lighthouse reported that role="button" did not support aria-expanded. That was true under ARIA 1.1, which the axe-core of that time used. ARIA 1.2 permits aria-expanded on the button role, so the override is no longer needed. A second commit in #9553 already replaced role="menu" on the dropdown toggles with role="link". The hamburger toggler was the one instance left.

The fix. Remove the role attribute. The button keeps aria-controls, aria-expanded, and its "Toggle navigation" label. This matches the markup in Bootstrap's own navbar documentation, which carries no role. A repo-wide search found no other role="menu", and no CSS, JS, or test keys off it.

Verification. With the two-file repro from the issue at a 600 px viewport: 1 axe-core violation (aria-allowed-role on .navbar-toggler) before the fix, 0 after, with best-practice rules on. After the fix, a click still flips aria-expanded to true and opens the collapse.

New test. A website smoke-all test (tests/docs/smoke-all/website/navbar-toggler-role/) asserts that the rendered toggler carries aria-expanded, aria-controls, and aria-label but no role attribute. The fix is a static template change, so no browser test is needed. The test fails against the old markup (verified by temporarily restoring role="menu").

Checklist

I have (if applicable):

  • referenced the GitHub issue this PR closes
  • updated the appropriate changelog in the PR
  • ensured the present test suite passes
  • added new tests
  • created a separate documentation PR in Quarto's website repo and linked it to this PR — not applicable: this PR changes internal navbar markup only, and no documented option or behavior changes
AI-assisted PR
  • AI tool used: Claude Code
  • Codebase grounding: local clone (git history of the template, repo-wide search, rendered repro)
  • Human review: I have reviewed, tested, and verified the AI-generated content before submitting.

Note: autonomous AI agents submitting PRs without human oversight are not permitted — see the Code of Conduct.

role="menu" was added to navtoggle.ejs in #9553 because Lighthouse
(running an older axe-core built on ARIA 1.1) reported that the button
role did not support aria-expanded. ARIA 1.2 allows aria-expanded on
button, so the override is no longer needed — and it was never a valid
role for the element: axe-core flags it as aria-allowed-role, and WAVE
treats a menu with no menuitem children as an Error (aria_menu_broken)
mapped to WCAG 2.2 SC 2.1.1 and 4.1.2. A follow-up commit in #9553
already replaced role="menu" on the dropdown toggles; the hamburger
toggler was the remaining instance.

The toggler now matches Bootstrap's own navbar-toggler markup: native
button semantics with aria-controls, aria-expanded, and aria-label.

Adds a website smoke-all regression test that asserts the rendered
toggler carries aria-expanded, aria-controls, and aria-label but no
role attribute.

Fixes #14615
@posit-snyk-bot

posit-snyk-bot commented Aug 24, 2026

Copy link
Copy Markdown
Collaborator

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

The 1.10 changelog established a dedicated Accessibility section for
this kind of entry. Also add /_site/ to the smoke-all fixture's
.gitignore: the harness cleans output after a run, but an interrupted
run would otherwise leave an untracked _site behind.
@cwickham
cwickham marked this pull request as ready for review August 25, 2026 18:28
@cwickham
cwickham requested a review from cderv August 25, 2026 18:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

a11y: collapsed navbar toggler has role="menu", an invalid role for a <button> (aria-allowed-role)

2 participants