refactor(ui): rebuild Tabs primitive on Button tabs and adopt across admin pages - #183
Merged
Conversation
…admin pages The Tabs compound component (ARIA automatic-activation, roving tabindex, keyboard nav) shipped with an underline visual style no page used, so it sat dead while AiPage, UsersPage, and AccountPage each hand-rolled the same Button-based tablist — with drift: UsersPage's tabs were missing role="tab"/aria-selected, none had arrow-key navigation, and all three duplicated the same .tabsRow CSS. - Tab now renders the shared Button primitive (primary when active, secondary otherwise, size sm) — the pattern the pages already used. - TabPanel lazy-mounts children by default (matching page behavior); keepMounted opts panels back into staying mounted while hidden. The panel element itself stays in the DOM so aria-controls always resolves. - Tab gains a testId prop so the pages' existing data-testids carry over. - AiPage, UsersPage, AccountPage adopt Tabs/TabList/TabPanel; the three .tabsRow copies are deleted. All three pages gain keyboard navigation, and UsersPage gains the ARIA it was missing. - usersAdmin tests updated: tab queries use role="tab" (a11y improvement the change delivers); new unit tests cover the primitive's contract. Verification: bun test (6009 pass), bun run build, bun run lint. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 task
DavidBabinec
marked this pull request as ready for review
July 31, 2026 13:07
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed
The
Tabscompound component (src/ui/components/Tabs/) shipped with WAI-ARIA automatic activation, roving tabindex, and arrow-key navigation, but had no consumers while Account and Users hand-rolled the same Button-based tablist.This PR rebuilds the primitive around the Button pattern those pages use, then adopts it in both:
Tabrenders the sharedButtonprimitive (primarywhen active,secondaryotherwise, sizesm).TabPanellazy-mounts children by default;keepMountedkeeps panel content mounted while hidden.aria-controlsresolves.Tabgains atestIdprop.TabListandTabPanelmay live in different subtrees of oneTabsprovider.main's redesigned AI settings sidebar and OAuth routing are preserved during conflict resolution.Why
A dead primitive coexisting with hand-rolled page tabs was causing accessibility and behavior drift. Consolidating the remaining tab pages adds correct ARIA plus ArrowLeft/ArrowRight/Home/End navigation.
Impact
Verification
bun test src/__tests__/ui/tabs.test.tsx src/__tests__/users/usersAdmin.test.tsx src/__tests__/admin/accountPage.test.tsx— 28 pass, 0 failbun run build— passbun run lint— passbun test— 6,494 pass; 11 localhost socket tests pass when rerun with port access; one unrelated current-main ContentPage bundle budget is 43 bytes over its existing 90,000-byte cap