feat(a11y): implement ARIA tablist pattern across all tab strips (#1031)#1045
Conversation
…ius#1031) Converts all seven tab-strip components from plain buttons to the W3C APG Tabs pattern: role="tablist" on the container, role="tab" with aria-selected and aria-controls on each button, role="tabpanel" with aria-labelledby on each panel, roving tabIndex, and arrow-key / Home / End navigation via a shared ariaTabKeyDown utility. Components updated: SettingsPanel, MeshComPanel (removes aria-pressed), PotaSotaPanel, DXFilterManager, ActivateFilterManager, PSKFilterManager, PSKReporterPanel. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
accius
left a comment
There was a problem hiding this comment.
Nice cleanup of the tablist pattern across all seven tab strips. The shared ariaTabKeyDown helper is exactly the kind of utility that should exist for this — arrow / Home / End wrapped behavior in one place, components just pass their tab-id array and the active state setter.
A few things I liked:
The roving tabIndex (0 on active, -1 on others) is the W3C APG pattern and means tab key skips the inactive tabs entirely — keyboard users don't have to step through every tab to leave the strip. The ref callback that populates tabRefs.current and the setActiveTab + .focus() move on arrow press completes the loop.
Dropping aria-pressed from MeshComPanel is correct — aria-pressed is the toggle-button pattern and was lying about what those tabs were. Replacing it with aria-selected + role="tab" is the right semantic.
MeshComPanel switching from conditional mount to hidden/display:none panels is the only non-trivial behavior change. It means all three tab subtrees stay mounted, which has a small memory cost but matches APG and gives screen readers stable aria-controls targets. I think that's the right tradeoff here — those panels are cheap.
PSKReporter only wires the tablist for the PSK panel mode (not for the wsjt/Decodes/QSOs mode) — that's a deliberate scope decision and reasonable. Worth a followup later but not blocking.
Good to merge.
K0CJH
Summary
src/utils/ariaTabKeyDown.jsutility for W3C APG arrow-key / Home / End navigationrole="tablist",role="tab"+aria-selected+aria-controls, rovingtabIndex,role="tabpanel"+aria-labelledbyaria-pressedfrom MeshComPanel (wrong pattern for tabs)Components updated: SettingsPanel (9 tabs), MeshComPanel, PotaSotaPanel, DXFilterManager, ActivateFilterManager, PSKFilterManager, PSKReporterPanel
Test plan
Closes #1031
🤖 Generated with Claude Code