Context: Three pages use library Tabs only for the visual strip, with content: null on every item, because React Router drives the actual panel content. They also each pass both selectedKey and defaultSelectedKey as a workaround for a library wrapper bug (see library issue). The TabPanel infrastructure is dead weight.
Scope:
Build web/src/components/TabBar.tsx: a flex row of clickable tabs with the same underline / hover styling as the library Tabs, exposing currentKey and onChange(key). No panels.
Migrate web/src/pages/Cases/CaseDetails/Tabs.tsx, web/src/pages/Profile/index.tsx, web/src/pages/Courts/CourtDetails/Description.tsx to use it.
web/src/pages/Cases/CaseDetails/Voting/VotingHistory.tsx is similar (local currentTab state with siblings reading it). Migrating it is optional but consistent.
Keep library Tabs in Settings/index.tsx since that one uses item.content properly.
Context: Three pages use library Tabs only for the visual strip, with content: null on every item, because React Router drives the actual panel content. They also each pass both selectedKey and defaultSelectedKey as a workaround for a library wrapper bug (see library issue). The TabPanel infrastructure is dead weight.
Scope:
Build web/src/components/TabBar.tsx: a flex row of clickable tabs with the same underline / hover styling as the library Tabs, exposing currentKey and onChange(key). No panels.
Migrate web/src/pages/Cases/CaseDetails/Tabs.tsx, web/src/pages/Profile/index.tsx, web/src/pages/Courts/CourtDetails/Description.tsx to use it.
web/src/pages/Cases/CaseDetails/Voting/VotingHistory.tsx is similar (local currentTab state with siblings reading it). Migrating it is optional but consistent.
Keep library Tabs in Settings/index.tsx since that one uses item.content properly.