Panel
Tabs
Shows one panel of content at a time, chosen from a row of tabs.
Import
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@booleanpress/ui/tabs"Usage
Tabs switch between views of the same thing, on one page. For a move to another page, use links or a navigation menu.
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@booleanpress/ui/tabs"
export function Mailer() {
return (
<Tabs defaultValue="overview">
<TabsList>
<TabsTrigger value="overview">Overview</TabsTrigger>
<TabsTrigger value="logs">Logs</TabsTrigger>
</TabsList>
<TabsContent value="overview">Delivered today: 1,284</TabsContent>
<TabsContent value="logs">The 50 most recent emails.</TabsContent>
</Tabs>
)
}Each TabsTrigger and its TabsContent share a value. It is uncontrolled with defaultValue, or controlled with value and onValueChange. TabsList takes variant: default is a filled bar with a raised selected tab; line is a row with an underline. orientation="vertical" on Tabs stacks the triggers; give Tabs flex-row to put the panel beside them. Only the active panel is in the page.
Examples
Basic
Three tabs, the first selected, each with its own panel.
Line
variant="line" removes the fill and underlines the selected tab.
Vertical
orientation="vertical" stacks the tabs; Up and Down Arrow move between them.
Disabled
A disabled tab keeps its place, is skipped by the arrow keys and cannot be selected.
Accessibility
- Semantics
- A
tablistoftabbuttons (aria-selected,aria-controls) and atabpanelnamed by its tab (aria-labelledby).aria-orientationis set on the list when vertical. - Labels
- The text of each tab is its name. Name an icon-only tab with
aria-label. If a page has more than one tab list, give eachTabsListanaria-label. - Focus
- The tab list is one tab stop: it is the selected tab, and the other tabs are reached with the arrow keys. Tab then moves into the active panel, which is itself focusable when it holds no focusable content.
- Known limits
- Selecting happens as focus moves (automatic activation). A panel that is slow to load should not be a tab: set
activationMode="manual"onTabsso the arrow keys move focus and Enter or Space selects. - The selected tab is shown by fill, shadow and weight, and in the line variant by the underline: the underline is 2 px. The state is also in
aria-selected.
- Selecting happens as focus moves (automatic activation). A panel that is slow to load should not be a tab: set
Keyboard
| Key | Behaviour |
|---|---|
| Tab | Moves focus into the tab list, onto the selected tab, then into the active panel. |
| Right Arrow | Moves to and selects the next tab, wrapping from the last to the first. |
| Left Arrow | Moves to and selects the previous tab, wrapping from the first to the last. |
| Down ArrowUp Arrow | In a vertical list, moves to the next or previous tab. |
| Home | Moves to the first tab. |
| End | Moves to the last tab. |
API
Tabs
Renders Radix Tabs.Root and passes it every other prop.
| Prop | Type | Default | Description |
|---|---|---|---|
activationMode | "manual" | "automatic" | Whether a tab is activated automatically or manually. | |
asChild | boolean | ||
defaultValue | string | The value of the tab to select by default, if uncontrolled | |
dir | "ltr" | "rtl" | The direction of navigation between toolbar items. | |
onValueChange | ((value: string) => void) | A function called when a new tab is selected | |
orientation | "horizontal" | "vertical" | horizontal | The orientation the tabs are layed out. Mainly so arrow navigation is done accordingly (left & right vs. up & down) |
value | string | The value for the selected tab, if controlled |
TabsList
Renders Radix Tabs.List and passes it every other prop.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | ||
loop | boolean |
TabsTrigger
Renders Radix Tabs.Trigger and passes it every other prop.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | ||
value | string | The value for the selected tab, if controlled |
TabsContent
Renders Radix Tabs.Content and passes it every other prop.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | ||
forceMount | true | Used to force mounting when more control is needed. Useful when controlling animation with React animation libraries. | |
value | string | The value for the selected tab, if controlled |
Also exported: tabsListVariants, the class names of TabsList's variants and sizes (cva), to give another element the same look.
Every part takes className, merged with its defaults by cn(), and ref, which reaches the element it renders.
Data attributes: data-slot="tabs" (Tabs), data-slot="tabs-list" (TabsList), data-slot="tabs-trigger" (TabsTrigger), data-slot="tabs-content" (TabsContent), and data-orientation, data-variant.
Theming
The selected tab is bg-card (not the page colour, which is grey in BooleanSMTP and would be darker than the list). Inactive labels are text-muted-foreground.
The tokens its classes read. Change their values in your theme, and it follows.
| Token | Used for |
|---|---|
--card | background |
--foreground | text, background |
--input | border, background |
--muted | background |
--muted-foreground | text |
--ring | border, focus ring, outline |