# Tabs

> Switches between related panels of content within the same page.

Category: Navigation · Status: stable · Package: @bindshq/stance-react@0.1.1 · Docs: https://stanceui.com/components/tabs

Use Tabs to divide one page’s content into peer sections, such as a template’s overview, assignees and history. Panels should not depend on each other. For moving between pages use TabBar, Sidebar or links; for a sequence of steps use Stepper.

## Import

```tsx
import { Tabs, TabsList, TabsTrigger, TabsContent } from '@bindshq/stance-react';
```

Styles are imported once per app: `@bindshq/stance-tokens/css` and `@bindshq/stance-react/styles.css`.

## Examples

### Basic

```tsx
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@bindshq/stance-react';

export function Basic() {
  return (
    <Tabs defaultValue="overview" style={{ width: '100%' }}>
      <TabsList aria-label="Template sections">
        <TabsTrigger value="overview">Overview</TabsTrigger>
        <TabsTrigger value="assignees">Assignees</TabsTrigger>
        <TabsTrigger value="history">History</TabsTrigger>
      </TabsList>
      <TabsContent value="overview">
        The Sales signature is live for 48 people across 3 teams.
      </TabsContent>
      <TabsContent value="assignees">Assign the template to users or whole teams.</TabsContent>
      <TabsContent value="history">Version 7 was published on 4 November 2026.</TabsContent>
    </Tabs>
  );
}
```

### Pill variant

A segmented look for switching views of the same data.

```tsx
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@bindshq/stance-react';

export function Pill() {
  return (
    <Tabs defaultValue="month" variant="pill">
      <TabsList aria-label="Reporting period">
        <TabsTrigger value="week">Week</TabsTrigger>
        <TabsTrigger value="month">Month</TabsTrigger>
        <TabsTrigger value="quarter">Quarter</TabsTrigger>
      </TabsList>
      <TabsContent value="week">1,204 signatures deployed this week.</TabsContent>
      <TabsContent value="month">4,918 signatures deployed this month.</TabsContent>
      <TabsContent value="quarter">13,560 signatures deployed this quarter.</TabsContent>
    </Tabs>
  );
}
```

### Icons and counts

```tsx
import { Icon, Tabs, TabsContent, TabsList, TabsTrigger } from '@bindshq/stance-react';

export function WithIconsAndCounts() {
  return (
    <Tabs defaultValue="active" style={{ width: '100%' }}>
      <TabsList aria-label="Users">
        <TabsTrigger value="active" icon={<Icon name="users" />} badge={48}>
          Active
        </TabsTrigger>
        <TabsTrigger value="invited" icon={<Icon name="mail" />} badge={5}>
          Invited
        </TabsTrigger>
        <TabsTrigger value="suspended" icon={<Icon name="lock" />} disabled>
          Suspended
        </TabsTrigger>
      </TabsList>
      <TabsContent value="active">48 people have an active signature.</TabsContent>
      <TabsContent value="invited">5 invitations are waiting to be accepted.</TabsContent>
      <TabsContent value="suspended">No suspended users.</TabsContent>
    </Tabs>
  );
}
```

### Vertical

Settings-style navigation; becomes horizontal below 640px.

```tsx
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@bindshq/stance-react';

export function Vertical() {
  return (
    <Tabs defaultValue="profile" orientation="vertical" style={{ width: '100%' }}>
      <TabsList aria-label="Settings">
        <TabsTrigger value="profile">Profile</TabsTrigger>
        <TabsTrigger value="organisation">Organisation</TabsTrigger>
        <TabsTrigger value="security">Security</TabsTrigger>
        <TabsTrigger value="billing">Billing</TabsTrigger>
      </TabsList>
      <TabsContent value="profile">Your name, photo and contact details.</TabsContent>
      <TabsContent value="organisation">Company name, domains and branding.</TabsContent>
      <TabsContent value="security">Two-factor authentication and sessions.</TabsContent>
      <TabsContent value="billing">Plan, invoices and payment method.</TabsContent>
    </Tabs>
  );
}
```

### Manual activation

Arrow keys move focus only; Enter or Space selects. Use when panels fetch data.

```tsx
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@bindshq/stance-react';

export function Manual() {
  return (
    <Tabs defaultValue="exchange" activationMode="manual" style={{ width: '100%' }}>
      <TabsList aria-label="Integrations">
        <TabsTrigger value="exchange">Exchange</TabsTrigger>
        <TabsTrigger value="google">Google Workspace</TabsTrigger>
        <TabsTrigger value="azure">Azure AD</TabsTrigger>
      </TabsList>
      <TabsContent value="exchange">Exchange relay is connected.</TabsContent>
      <TabsContent value="google">Connect Google Workspace to sync users.</TabsContent>
      <TabsContent value="azure">Azure AD sync runs every 6 hours.</TabsContent>
    </Tabs>
  );
}
```

## API reference

| Component | Prop | Type | Default | Description |
| --- | --- | --- | --- | --- |
| Tabs | `value` | `string` | None | Controlled selected tab. |
| Tabs | `defaultValue` | `string` | None | Initially selected tab when uncontrolled. |
| Tabs | `onValueChange` | `(value: string) => void` | None | Called when the selected tab changes. |
| Tabs | `orientation` | `'horizontal' \| 'vertical'` | `'horizontal'` | Layout and arrow-key axis. |
| Tabs | `activationMode` | `'automatic' \| 'manual'` | `'automatic'` | Whether focusing a tab selects it. |
| Tabs | `variant` | `'line' \| 'pill'` | `'line'` | Underline or filled indicator. |
| Tabs | `size` | `'sm' \| 'md'` | `'md'` | Trigger height. |
| TabsList | `loop` | `boolean` | `true` | Wrap focus from last to first. |
| TabsList | `fullWidth` | `boolean` | `false` | Stretch triggers to fill the width. |
| TabsList | `aria-label` | `string` | None | Name for the tab set; required when a page has several. |
| TabsTrigger | `value` (required) | `string` | None | Identifies the tab and its panel. |
| TabsTrigger | `icon` | `ReactNode` | None | Icon before the label. |
| TabsTrigger | `badge` | `ReactNode` | None | Trailing count. |
| TabsTrigger | `disabled` | `boolean` | None | Skips the tab in keyboard navigation. |
| TabsContent | `value` (required) | `string` | None | Matches a trigger value. |
| TabsContent | `forceMount` | `boolean` | `false` | Keep the panel mounted while hidden to preserve its state. |

## Accessibility

- Implements the WAI-ARIA tabs pattern: tablist, tab and tabpanel roles with aria-selected, aria-controls and aria-labelledby.
- Only the selected tab is in the Tab order; arrow keys move between tabs and disabled tabs are skipped.
- Panels are focusable (tabindex 0) so keyboard users can reach content that has no interactive elements.
- High-contrast mode thickens the indicator and fills pill tabs so the selection never relies on subtle tints.

## Keyboard

| Keys | Action |
| --- | --- |
| `Tab` | Moves focus into the tab list, then to the active panel. |
| `←` `→` | Moves between tabs (horizontal). |
| `↑` `↓` | Moves between tabs (vertical). |
| `Home` `End` | First / last tab. |
| `Enter` `Space` | Selects the focused tab (manual mode). |

## Guidelines

**Do**

- Use short, parallel labels.
- Keep the most used panel first.

**Don’t**

- Nest tabs inside tabs.
- Use tabs for steps that must be completed in order.

## Related

- https://stanceui.com/components/tab-bar
- https://stanceui.com/components/stepper
- https://stanceui.com/components/accordion
