> For the complete documentation index, see [llms.txt](https://analog.groupthought.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://analog.groupthought.com/reference/alpine/tabs.md).

# x-tabs

Directives and magics for accessible tabs, built on disclosure groups.

Directives and magics for accessible tabs, built on [disclosure groups](/reference/alpine/disclosure.md).

| Directive / magic               | What it does                                                                                                    |
| ------------------------------- | --------------------------------------------------------------------------------------------------------------- |
| `x-tabs`                        | The root. A single-select disclosure group; the first tab is selected by default                                |
| `x-tabs.vertical`               | Vertical tab list: up/down arrow keys, `aria-orientation="vertical"`                                            |
| `x-tabs="{ selectedIndex: 1 }"` | Options object. `selectedIndex` accepts a get/set pair                                                          |
| `x-tabs:tablist`                | Wraps the tab buttons (`role="tablist"`, roving tab order)                                                      |
| `x-tabs:tab`                    | A tab button (`role="tab"`, `aria-selected`, `aria-controls`)                                                   |
| `x-tabs:tab="2"`                | Explicit index, for when DOM order may not match tab order                                                      |
| `x-tabs:tabpanel`               | A panel (`role="tabpanel"`), backed by `x-disclosure`                                                           |
| `x-tabs:tabpanel="2"`           | Explicit index matching its tab                                                                                 |
| `$tabs`                         | The state, readable anywhere inside the root: `select(index)`, `isSelected(index)`, `selectedIndex`, `tabCount` |
| `$tab`                          | Inside a tab or panel: `select()`, `isSelected`, `index`                                                        |

Arrow keys move through the tabs with a roving tabindex. Only the selected tab is in the page's tab sequence. Home and End move to the first and last tabs. Focusing a tab selects it, except on touch devices where selection happens on tap. The selected panel gets `tabindex="0"` so keyboard users can move from the tab into its content.

## Examples

### Basic tabs

Use `x-tabs:tab` buttons in a `x-tabs:tablist`, with one `x-tabs:tabpanel` per tab:

```html
<div x-tabs>
  <ul x-tabs:tablist>
    <li><button type="button" x-tabs:tab>Details</button></li>
    <li><button type="button" x-tabs:tab>Shipping</button></li>
  </ul>
  <div x-tabs:tabpanel>Panel 1</div>
  <div x-tabs:tabpanel x-cloak>Panel 2</div>
</div>
```

Tabs and panels pair up by order: the first tab controls the first panel. Put `x-cloak` on every panel except the first so they stay hidden until Alpine starts.

### Styling the selected tab

Use `$tab.isSelected` on a tab or panel to style the active state:

```html
<button type="button" x-tabs:tab :data-state="$tab.isSelected ? 'active' : 'inactive'">
  …
</button>
```

The `core-tab` snippet renders its buttons this way, and the tab blocks use the same binding on their panels.

### Explicit indices

Use an index expression on each tab and panel when DOM order cannot be trusted:

```html
<div x-tabs>
  <ul x-tabs:tablist>
    <li><button type="button" x-tabs:tab="0">Details</button></li>
    <li><button type="button" x-tabs:tab="1">Shipping</button></li>
  </ul>
  <div x-tabs:tabpanel="0">Panel 1</div>
  <div x-tabs:tabpanel="1" x-cloak>Panel 2</div>
</div>
```

Use this when a section reload can register elements out of order. The explicit index wins over registration order.

### Opening on a specific tab

Use the `selectedIndex` option to pick the opening tab, or a get/set pair to bind the selection to your own state:

```html
<div x-tabs="{ selectedIndex: 1 }">…</div>
```

### Vertical tabs

Use the `vertical` modifier for a stacked tab list:

```html
<div x-tabs.vertical>…</div>
```

Up and down arrow keys move through the tabs, and the tablist reports `aria-orientation="vertical"`.

## Options

| Option          | What it does                                                               |
| --------------- | -------------------------------------------------------------------------- |
| `selectedIndex` | The selected tab (default `0`). Accepts a get/set pair for two-way binding |

Panels use disclosures, so `$disclosure` also works inside them. See [x-disclosure](/reference/alpine/disclosure.md). In Analog, build tab UIs with the `core-tabs`, `core-tablist`, and `core-tab` snippets, which include the theme's tab styles and settings. To sync tabs with a slideshow in a Pair section, see [Pair sections](/building-pages/pair.md).
