---
title: "Tabs"
description: "A pill-style tab list that switches the active tab on click."
---

A pill tab group. The panel is only rendered for the active tab, so a tab whose content is expensive does not cost anything until it is opened.

_Live example of Tabs — see the page for the rendered demo._

## Installation

```bash
npx newtui@latest add tabs
```

Files written — React: components/ui/tabs.tsx. Vue: components/ui/tabs/Tabs.vue, components/ui/tabs/TabsTrigger.vue, components/ui/tabs/TabsContent.vue, components/ui/tabs/index.ts.

## Usage

React:

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

Vue:

```ts
import { Tabs, TabsTrigger, TabsContent } from "@/components/ui/tabs"
```

## API reference

**`Tabs`**

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `value` | `string` | — | The active tab, when you control it. |
| `defaultValue` | `string` | — | The tab active on first render, when you do not. |
| `onValueChange` | `(value: string) => void` | — | Called with the tab that was activated. |

**`TabsTrigger`**

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `value` | `string` | — | Which panel this trigger opens. |
| `disabled` | `boolean` | `false` | Skipped by arrow-key navigation. |

**`TabsContent`**

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `value` | `string` | — | Which trigger opens this panel. |

Every part also accepts the native attributes of the element it renders, and a `className` that is merged rather than replaced.

## Accessibility

It implements the tabs pattern: `role="tablist"`, `aria-selected` on the triggers, `aria-controls` and `aria-labelledby` linking each pair. Only the active trigger is in the tab order; `Left` and `Right` move between triggers, `Home` and `End` jump to the ends.

## Tokens

Tabs reads its colours, radii and motion from the `--newt-*` tokens. Override a token rather than editing the component.
