Accessibility
Tabs from @prepared911/ui/tabs implements the WAI-ARIA Tabs pattern. Trigger-to-panel association, orientation, roving focus, and keyboard behavior are built in; your job is to name the tab list and to keep focus behavior inside panels sensible.
TabsList → tablist, TabsTrigger → tab with aria-selected and aria-controls, TabsContent → tabpanel with aria-labelledby.aria-orientation on the tab list reflects horizontal or vertical layout and drives arrow-key direction.activation={TabsActivation.Manual} keeps arrows on focus until Enter or Space.listOverflow={TabsListOverflow.Scroll}, arrow-key roving focus is unchanged. When focus moves to a tab outside the visible scrollport, the list scrolls that tab into view (scrollIntoView). Scroll padding and clip margin reserve space so focus rings stay visible at the edges of the scrollport (WCAG 2.4.11).fill on panel Tabs, the root grows in a flex parent and each TabsContent panel scrolls inside itself.TabsList, set label (LocalizedMessage, rendered as aria-label) or aria-labelledby. The panel-mode Tabs root has no role; the accessible name belongs on the tablist, not on a wrapper div.aria-label.getByRole("tablist", { name: "…" })getByRole("tab", { name: "…" })getByRole("tabpanel", { name: "…" }) (the panel name comes from the tab that labels it)Tabs, TabsList, or TabsContent in extra elements just to attach data-test-id or to query structure. Do not disable testing-library/no-node-access to reach into a design-system tab; if a part is not findable by role, treat that as a design-system defect.
| Key | Action |
|---|---|
| Tab | Moves focus into the active trigger, then into the panel. |
| Arrow Left / Right | Moves between triggers in horizontal layouts. |
| Arrow Up / Down | Moves between triggers in vertical layouts. |
| Enter / Space | Activates the focused trigger (manual mode selects). |
| Home / End | Jumps to the first / last trigger. |
| Element | Role | Key attributes |
|---|---|---|
TabsList | tablist | aria-orientation, accessible name |
TabsTrigger | tab | aria-selected, aria-controls |
TabsContent | tabpanel | aria-labelledby |
TabsListOverflow.Scroll), roving focus does not trap inside the scrollport: Home, End, and arrow keys still move among all tabs, and the list scrolls to keep the focused tab visible.tabpanel can confuse assistive tech.Dialog; never rely on a tab change to "cancel" a destructive flow.