# Tabs

> Views of one thing: the underline or pill is thrown to the new tab, the panel slides in from the side you moved toward, and counts roll.

Tabs usually swap their panel in one frame and blink the highlight from tab to tab, so the page jumps. Here the indicator is thrown to the new tab while its width eases, the new panel slides in from the direction you moved as the old one leaves the other way, and the box eases to the new height. Counts on tabs roll when they change.

## Install

```bash
npx shadcn@latest add https://hairlineui.com/r/tabs.json
```

Needs React 19, Tailwind CSS v4 and shadcn/ui theme variables (any style, light and dark). Icons from lucide-react.

- npm: none
- Hairline UI components it needs (the CLI installs them too): `number-roll`, `ui-interaction-motion`
- Docs and live preview: https://hairlineui.com/ui/tabs
- Registry item (source): https://hairlineui.com/r/tabs.json

## Usage

```tsx
import { Tabs } from "@/components/ui/tabs";

<Tabs label="Settings" items={[
  { value: "general", label: "General", content: <General /> },
  { value: "billing", label: "Billing", content: <Billing /> },
  { value: "members", label: "Members", count: 8, content: <Members /> },
]} />
```

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `items` | `TabItem[]` | – | value, label, icon, count, content, disabled. |
| `value / defaultValue` | `string` | – | Chosen tab. |
| `onValueChange` | `(value: string) => void` | – | Called on change. |
| `variant` | `"underline" \| "pills"` | `"underline"` | Look of the indicator. |
| `label` | `string` | – | Accessible name of the tablist. |

## States

- **pick**: Indicator thrown (440ms, slight overshoot), width eased (400ms).
- **panel**: New panel slides 20px out of a 4px blur (380ms); old one leaves the other way (200ms); height eases (380ms).
- **keys**: Arrows move and select; Home and End jump.

## What it handles

A tab change is a change of view; when the panel just swaps, people lose their place. The direction of the slide tells them where they went.

- **Thrown indicator**: Measured from layout; overshoot on position, eased width.
- **Directional panels**: Enter from the side you moved toward, leave the other way, height eased.
- **Rolling counts**: NumberRoll on each tab's count.
- **Scrolls on phones**: The strip scrolls the chosen tab into view, never the page.

## Replaces

Radix Tabs, sliding underline, animated tab panels

## Where it fits

- **Settings pages**: General, Billing, Members as one page.
- **Dashboards**: Overview, Traffic, Revenue for one site.
- **Inbox filters**: All, Unread (12), Archived with live counts.
- **Product details**: Description, Specs, Reviews.

## Notes

- tablist, tab and tabpanel roles, aria-selected and aria-controls.
- Reduced motion: the indicator and panel change in place.
- Use the segmented control when there are no panels.

License: MIT (https://hairlineui.com/license#components)
