openedx / openedx/paragon

a11y: Tabs — tabs and tabpanels are not programmatically associated; other APG tabs-pattern deviations

Open
#4,404 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
JavaScript
Stars
140
Forks
100
Avg merge
1h 3m
Merged PRs (30d)
30

Description

Context

Found during the 2026 Axim-commissioned accessibility audit of Paragon, while documenting Tabs against the APG tabs pattern.

Current behavior (from src/Tabs/__snapshots__/Tabs.test.jsx.snap and React-Bootstrap 1.6.5)

  1. No tab↔panel association. Tab panels render role="tabpanel" with aria-labelledby={null}, and tabs render role="tab" with no aria-controls (no id linkage in either direction).
  2. No roving tabindex. Every tab is an <a href="#"> and remains in the page tab sequence; the APG pattern expects a single tab stop for the tablist with arrow-key navigation inside. Arrow keys do work (React-Bootstrap AbstractNav: Left/Up previous, Right/Down next, selection follows focus), but Home/End are unsupported and Space does not activate (anchor semantics).
  3. Overflow "More..." control. The responsive overflow renders a <button aria-haspopup="true"> nested inside an <a role="tab"> that has no aria-selected — nested interactive elements, and a tab that isn't a tab. Hidden tabs are exposed as dropdown items rather than tabs.

Impact

  • (1) Screen reader users landing in a panel get no announcement of which tab labels it; some AT navigation shortcuts between tab and panel don't work. WCAG 1.3.1 Info and Relationships, 4.1.2 Name, Role, Value.
  • (2) Extra tab stops slow keyboard traversal of pages with many tabs; missing Space activation is inconsistent with the announced role.
  • (3) The nested-interactive structure produces unpredictable focus/announcement behavior in the overflow case.

Suggested direction

Generate stable ids per tab/panel and wire aria-controls/aria-labelledby (fixes 1 without behavior change); consider roving tabindex and Home/End as a follow-up; rework the overflow control so the "More..." toggle is not inside a role="tab" element.

References

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the current behavior captured in src/Tabs/snapshots/Tabs.test.jsx.snap and the React-Bootstrap AbstractNav keyboard behavior. Implement stable tab/panel ids with aria-controls and aria-labelledby, then address the roving-tabindex and overflow-control deviations described in the issue. Done means the Tabs markup follows the referenced APG relationships without nested interactive controls.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, react
Domain
accessibility, frontend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.