---
title: Tabs
description: Organize related content into switchable panels readers can flip between.
---

Use `<Tabs>` to organize content into switchable panels. Add any number of `<TabItem>` children and include other content (code blocks, callouts, or lists) inside each panel.

Each `<TabItem>` needs a `label` (what readers see) and a `value` (a stable ID for defaults, sync, and persistence). Keep `value` fixed even if you rename the label.

```mdx
<Tabs>
  <TabItem label="First" value="first">Content here</TabItem>
</Tabs>
```

## Example

<Tabs>
  <TabItem label="First tab" value="first">
    Welcome to the content inside the first tab.

    You can nest other components inside tabs. For example, a code block:

    ```js
    export function greet(name) {
      return `Hello, ${name}!`;
    }
    ```
  </TabItem>
  <TabItem label="Second tab" value="second">
    Panels can contain lists too:

    - Install dependencies
    - Configure your project
    - Deploy
  </TabItem>
  <TabItem label="Third tab" value="third">
    <Info>
      Callouts and other components work inside tabs as well.
    </Info>
  </TabItem>
</Tabs>

````mdx
<Tabs>
  <TabItem label="First tab" value="first">
    Welcome to the content inside the first tab.

    You can nest other components inside tabs. For example, a code block:

    ```js
    export function greet(name) {
      return `Hello, ${name}!`;
    }
    ```
  </TabItem>
  <TabItem label="Second tab" value="second">
    Panels can contain lists too:

    - Install dependencies
    - Configure your project
    - Deploy
  </TabItem>
  <TabItem label="Third tab" value="third">
    <Info>
      Callouts and other components work inside tabs as well.
    </Info>
  </TabItem>
</Tabs>
````

## Properties

### `Tabs`

<Property name="defaultValue" type="string" optional>
  The tab to show on first load. Must match a `TabItem` `value`.

  Defaults to the first tab.
</Property>

---

<Property name="groupId" type="string" optional>
  A shared identifier for synchronized tab groups. Tabs with the same `groupId` stay in sync by matching `value` values across groups.

  When set, the selected tab is stored in local storage and restored on reload. Preview mode uses the key `preview:tabs:{groupId}`; published docs use `docs.page:tabs:{owner}/{repository}:{groupId}`.
</Property>

### `TabItem`

<Property name="label" type="string" required>
  The text shown on the tab trigger. Use short, scannable labels such as **JavaScript** or **CLI**.
</Property>

---

<Property name="value" type="string" required>
  A stable identifier for the tab within its group. Used by `defaultValue` and by `groupId` synchronization across tab groups.

  Choose a `value` that won't change when you edit the label, for example `label="JavaScript"` with `value="js"`.
</Property>

## Synchronization

Tab groups are independent by default. To keep multiple groups in sync, set the same `groupId` on each `<Tabs>` and use the same `value` on corresponding `<TabItem>` children.

Use this when the same options appear in more than one place, for example language-specific install steps and matching API examples.

The example below uses two groups that share `groupId="language"`. Selecting **JavaScript** in either group selects **JavaScript** in both.

<Tabs groupId="language">
  <TabItem label="JavaScript" value="js">
    ```js
    import axios from 'axios';
    ```
  </TabItem>
  <TabItem label="Dart" value="dart">
    ```dart
    import 'package:dio/dio.dart';
    ```
  </TabItem>
</Tabs>

<Tabs groupId="language">
  <TabItem label="JavaScript" value="js">
    ```js
    const response = await axios.get('https://example.com');
    ```
  </TabItem>
  <TabItem label="Dart" value="dart">
    ```dart
    final response = await Dio().get('https://example.com');
    ```
  </TabItem>
</Tabs>

````mdx
<Tabs groupId="language">
  <TabItem label="JavaScript" value="js">...</TabItem>
  <TabItem label="Dart" value="dart">...</TabItem>
</Tabs>

<Tabs groupId="language">
  <TabItem label="JavaScript" value="js">...</TabItem>
  <TabItem label="Dart" value="dart">...</TabItem>
</Tabs>
````

## Behavior

| Condition | Result |
| --- | --- |
| No valid `<TabItem>` children | Renders nothing |
| Selected `value` is not in the current group | Falls back to `defaultValue`, then the first tab |
| `defaultValue` does not match any `value` | Falls back to the first tab |
| `groupId` omitted | Tab groups on the page operate independently |
| `groupId` set | Selection syncs across groups and persists in local storage on reload |

## See also

- [Code group](/components/code-group): tabbed code blocks for language switching
- [Accordion](/components/accordion): collapsible sections for optional detail
- [Components overview](/components): when to use tabs, code groups, and accordions
