Skip to content

refactor(ui): rebuild Tabs primitive on Button tabs and adopt across admin pages - #183

Merged
DavidBabinec merged 4 commits into
mainfrom
refactor/tabs-primitive
Jul 31, 2026
Merged

refactor(ui): rebuild Tabs primitive on Button tabs and adopt across admin pages#183
DavidBabinec merged 4 commits into
mainfrom
refactor/tabs-primitive

Conversation

@DavidBabinec

@DavidBabinec DavidBabinec commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

What changed

The Tabs compound 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:

  • Tab renders the shared Button primitive (primary when active, secondary otherwise, size sm).
  • TabPanel lazy-mounts children by default; keepMounted keeps panel content mounted while hidden.
  • The panel element always remains in the DOM so the active tab's aria-controls resolves.
  • Tab gains a testId prop.
  • TabList and TabPanel may live in different subtrees of one Tabs provider.
  • Account and Users adopt the primitive and delete their duplicated tab-row CSS.
  • Current 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

  • Account and Users keep their existing visual treatment.
  • Both pages gain shared roving-tabindex and automatic keyboard activation.
  • Users tabs now expose the correct tab roles.
  • The newer AI settings workspace remains unchanged.

Verification

  • bun test src/__tests__/ui/tabs.test.tsx src/__tests__/users/usersAdmin.test.tsx src/__tests__/admin/accountPage.test.tsx — 28 pass, 0 fail
  • bun run build — pass
  • bun run lint — pass
  • Full bun 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
  • Browser smoke test on disposable SQLite data at 1440×900 — Account and Users tab rendering, click activation, ArrowRight/Home/End activation, focus movement, and panel switching pass; no page or console errors

DavidBabinec and others added 2 commits July 3, 2026 23:21
…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>
@DavidBabinec
DavidBabinec marked this pull request as ready for review July 31, 2026 13:07
@DavidBabinec
DavidBabinec merged commit d35db99 into main Jul 31, 2026
8 of 9 checks passed
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.

1 participant