Tabs
A set of layered sections of content that display one panel at a time.
1<Flex2 direction="row"3 gap={9}4 style={{ width: "100%", fontSize: "12px", padding: "0 16px" }}5>6 <Tabs defaultValue="tab-one">7 <Tabs.List>8 <Tabs.Tab value="tab-one">Hosting</Tabs.Tab>9 <Tabs.Tab value="tab-two">Billing</Tabs.Tab>10 <Tabs.Tab value="tab-three">SEO</Tabs.Tab>11 </Tabs.List>12 <Tabs.Content value="tab-one">13 <Text>Hosting configuration content</Text>14 </Tabs.Content>15 <Tabs.Content value="tab-two">
Anatomy
Import and assemble the component:
1import { Tabs } from "@raystack/apsara";23<Tabs>4 <Tabs.List>5 <Tabs.Tab />6 </Tabs.List>7 <Tabs.Content />8</Tabs>
Usage
Tabs are a list of triggers and the panels they show. Appearance is set on the root.
Basic usage
A tab list with panels. Set defaultValue to the tab that should open first.
1<div style={{ width: "400px" }}>2 <Tabs defaultValue="tab1">3 <Tabs.List>4 <Tabs.Tab value="tab1">Account</Tabs.Tab>5 <Tabs.Tab value="tab2">Password</Tabs.Tab>6 <Tabs.Tab value="tab3">Settings</Tabs.Tab>7 </Tabs.List>8 <Tabs.Content value="tab1">Account settings</Tabs.Content>9 <Tabs.Content value="tab2">Password settings</Tabs.Content>10 <Tabs.Content value="tab3">Other settings</Tabs.Content>11 </Tabs>12</div>
Variants
Three treatments. segmented groups the tabs in a track, standalone gives them an underline, and plain strips the chrome for dense layouts.
1<div style={{ width: "400px" }}>2 <Tabs defaultValue="tab1">3 <Tabs.List>4 <Tabs.Tab value="tab1">Account</Tabs.Tab>5 <Tabs.Tab value="tab2" disabled>6 Password7 </Tabs.Tab>8 <Tabs.Tab value="tab3">Settings</Tabs.Tab>9 </Tabs.List>10 <Tabs.Content value="tab1">Account settings</Tabs.Content>11 <Tabs.Content value="tab2">Password settings</Tabs.Content>12 <Tabs.Content value="tab3">Other settings</Tabs.Content>13 </Tabs>14</div>
Sizes
Three sizes. medium is the default; use small in toolbars and panels.
1<div style={{ width: "400px" }}>2 <Tabs defaultValue="tab1" size="small">3 <Tabs.List>4 <Tabs.Tab value="tab1">Account</Tabs.Tab>5 <Tabs.Tab value="tab2" disabled>6 Password7 </Tabs.Tab>8 <Tabs.Tab value="tab3">Settings</Tabs.Tab>9 </Tabs.List>10 <Tabs.Content value="tab1">Account settings</Tabs.Content>11 <Tabs.Content value="tab2">Password settings</Tabs.Content>12 <Tabs.Content value="tab3">Other settings</Tabs.Content>13 </Tabs>14</div>
With leading icons
Pass leadingIcon on a trigger to place an icon before its label.
1<div style={{ width: "400px" }}>2 <Tabs defaultValue="tab1">3 <Tabs.List>4 <Tabs.Tab value="tab1">Home</Tabs.Tab>5 <Tabs.Tab value="tab2" leadingIcon={<Info />}>6 Info7 </Tabs.Tab>8 </Tabs.List>9 <Tabs.Content value="tab1">Home content</Tabs.Content>10 <Tabs.Content value="tab2">Info content</Tabs.Content>11 </Tabs>12</div>
Disabled tab
Set disabled on a trigger to keep a tab visible but unreachable.
1<div style={{ width: "400px" }}>2 <Tabs defaultValue="tab1">3 <Tabs.List>4 <Tabs.Tab value="tab1">Active</Tabs.Tab>5 <Tabs.Tab value="tab2" disabled>6 Disabled7 </Tabs.Tab>8 </Tabs.List>9 <Tabs.Content value="tab1">Active tab content</Tabs.Content>10 <Tabs.Content value="tab2">Disabled tab content</Tabs.Content>11 </Tabs>12</div>
Controlled
Pass value with onValueChange to own the active tab — needed when something outside the tab list has to switch panels, or when the tab is part of the URL.
1(function ControlledTabs() {2 const [tab, setTab] = React.useState("overview");34 return (5 <Flex direction="column" gap={5} style={{ width: "100%" }}>6 <Tabs value={tab} onValueChange={setTab}>7 <Tabs.List>8 <Tabs.Trigger value="overview">Overview</Tabs.Trigger>9 <Tabs.Trigger value="usage">Usage</Tabs.Trigger>10 </Tabs.List>11 <Tabs.Content value="overview">Overview panel</Tabs.Content>12 <Tabs.Content value="usage">Usage panel</Tabs.Content>13 </Tabs>14 <Button size="small" onClick={() => setTab("usage")}>15 Go to Usage
API Reference
The tab list, and one content panel per tab.
Root
Groups all parts of the tabs component.
Prop
Type
List
Renders the tab navigation bar.
Prop
Type
Tab
Renders an individual tab button.
Prop
Type
Content
Renders the content panel for a tab.
Prop
Type
Slots
Every rendered part carries a stable data-slot attribute for styling and testing:
| Slot | Element |
|---|---|
tabs | The root element |
tabs-list | Tabs.List container |
tabs-indicator | The animated active-tab indicator |
tabs-tab | Tabs.Tab button |
tabs-tab-icon | A tab's leading icon (when leadingIcon is set) |
tabs-content | Tabs.Content panel |
Accessibility
- Follows the WAI-ARIA Tabs pattern
- Supports keyboard navigation with arrow keys between tabs
- Uses
role="tablist",role="tab", androle="tabpanel" - Active tab is indicated with
aria-selected - Leading icon is wrapped with
aria-hiddenso it is not announced (treated as decorative) - Respects motion preferences: tab indicator motion is enabled only when
prefers-reduced-motion: no-preference