# `PUI.Tabs`

Accessible tabs for switching between related panels of content.

PUI tabs follow the shadcn/ui visual language while keeping a Phoenix-friendly,
server-renderable API. The component renders correct WAI-ARIA roles and states
on the server, then enhances the experience with the `PUI.Tabs` hook for arrow
key navigation, roving focus, and optional client-side activation.

Use `tabs/1` with `:trigger` and optional `:content` slots. Triggers and
panels are matched by their shared `value`.

When you only need trigger buttons (e.g. a segmented control or toolbar), omit
the `:content` slots entirely — the component will not render the extra spacing
or panels wrapper.

## Basic Usage

    <.tabs id="account-tabs" default_value="account">
      <:trigger value="account">Account</:trigger>
      <:trigger value="password">Password</:trigger>
      <:content value="account">
        Make changes to your account here.
      </:content>
      <:content value="password">
        Change your password here.
      </:content>
    </.tabs>

## Trigger-Only Usage

Omit `:content` slots for segmented controls, toolbars, or any scenario where
you only need the tab triggers:

    <.tabs id="view-tabs" default_value="grid">
      <:trigger value="grid">Grid</:trigger>
      <:trigger value="list">List</:trigger>
    </.tabs>

    <.tabs id="account-tabs" default_value="account">
      <:trigger value="account">Account</:trigger>
      <:trigger value="password">Password</:trigger>
      <:content value="account">
        Make changes to your account here.
      </:content>
      <:content value="password">
        Change your password here.
      </:content>
    </.tabs>

## Server-Controlled Tabs

Set `value` from your assigns and push a LiveView event from each trigger when
you want the server to be the source of truth:

    <.tabs id="settings-tabs" value={@active_tab} client_controlled={false}>
      <:trigger value="profile" phx-click="select_tab" phx-value-tab="profile">
        Profile
      </:trigger>
      <:trigger value="billing" phx-click="select_tab" phx-value-tab="billing">
        Billing
      </:trigger>
      <:content value="profile">Profile settings...</:content>
      <:content value="billing">Billing settings...</:content>
    </.tabs>

## Vertical Tabs

    <.tabs id="preferences-tabs" default_value="notifications" orientation="vertical">
      <:trigger value="notifications">Notifications</:trigger>
      <:trigger value="security">Security</:trigger>
      <:content value="notifications">Notification preferences...</:content>
      <:content value="security">Security preferences...</:content>
    </.tabs>

## Attributes

| Attribute | Type | Default | Description |
|-----------|------|---------|-------------|
| `id` | `string` | auto-generated | Unique id used to link tabs and panels |
| `value` | `string` | `nil` | Active value when the server controls selection |
| `default_value` | `string` | first enabled trigger | Initial active value for client-controlled tabs |
| `orientation` | `string` | `"horizontal"` | `"horizontal"` or `"vertical"` |
| `activation_mode` | `string` | `"manual"` | `"automatic"` or `"manual"` keyboard activation |
| `client_controlled` | `boolean` | `true` | Whether the hook updates active state in the browser |
| `variant` | `string` | `"default"` | `"default"`, `"line"`, or `"unstyled"` |
| `class` | `string` | `""` | Additional root classes |
| `list_class` | `string` | `""` | Additional classes for the tab list |
| `panels_class` | `string` | `""` | Additional classes for the panels wrapper |

## Trigger Slot Attributes

| Attribute | Type | Default | Description |
|-----------|------|---------|-------------|
| `value` | `string` | **required** | Tab value used to match a panel |
| `id` | `string` | generated | Custom trigger id |
| `class` | `string` | `""` | Additional trigger classes |
| `disabled` | `boolean` | `false` | Disables pointer and keyboard activation |
| `phx-click` | `any` | `nil` | LiveView event or JS command for server-controlled tabs |
| `phx-target` | `any` | `nil` | Optional event target |
| `phx-value-tab` | `string` | `nil` | Tab value sent with `phx-click` |

## Content Slot Attributes

| Attribute | Type | Default | Description |
|-----------|------|---------|-------------|
| `value` | `string` | **required** | Panel value matched with a trigger |
| `id` | `string` | generated | Custom panel id |
| `class` | `string` | `""` | Additional panel classes |

## Accessibility

- Uses `role="tablist"`, `role="tab"`, and `role="tabpanel"`
- Supports roving focus with arrow keys, `Home`, and `End`
- Defaults to manual activation so arrow keys move focus and `Space`/`Enter` activate
- Supports automatic and manual activation modes
- Keeps inactive panels hidden from assistive technology and visual layout

# `tabs`

Renders an accessible tabs interface with server and client control modes.

The server renders the active tab state for the initial response, while the
`PUI.Tabs` hook adds keyboard support and optional browser-managed activation.

## Examples

    <.tabs id="team-tabs" default_value="members">
      <:trigger value="members">Members</:trigger>
      <:trigger value="billing">Billing</:trigger>
      <:content value="members">Manage team members.</:content>
      <:content value="billing">Manage billing details.</:content>
    </.tabs>

    <.tabs id="live-tabs" value={@active_tab} client_controlled={false}>
      <:trigger value="overview" phx-click="select_tab" phx-value-tab="overview">
        Overview
      </:trigger>
      <:trigger value="activity" phx-click="select_tab" phx-value-tab="activity">
        Activity
      </:trigger>
      <:content value="overview">Overview panel.</:content>
      <:content value="activity">Activity panel.</:content>
    </.tabs>

## Trigger-Only Tabs (no content panels)

When you only need the tab triggers as a segmented control or toolbar,
omit the `:content` slots entirely:

    <.tabs id="view-tabs" default_value="grid">
      <:trigger value="grid">Grid</:trigger>
      <:trigger value="list">List</:trigger>
    </.tabs>

## Attributes

* `id` (`:string`) - Defaults to `nil`.
* `value` (`:string`) - Defaults to `nil`.
* `default_value` (`:string`) - Defaults to `nil`.
* `orientation` (`:string`) - Defaults to `"horizontal"`. Must be one of `"horizontal"`, or `"vertical"`.
* `activation_mode` (`:string`) - Defaults to `"manual"`. Must be one of `"automatic"`, or `"manual"`.
* `client_controlled` (`:boolean`) - Defaults to `true`.
* `variant` (`:string`) - Defaults to `"default"`. Must be one of `"default"`, `"line"`, or `"unstyled"`.
* `class` (`:string`) - Defaults to `""`.
* `list_class` (`:string`) - Defaults to `""`.
* `panels_class` (`:string`) - Defaults to `""`.
* Global attributes are accepted.
## Slots

* `trigger` (required) - Accepts attributes:

  * `value` (`:string`) (required)
  * `id` (`:string`)
  * `class` (`:string`)
  * `disabled` (`:boolean`)
  * `phx-click` (`:any`)
  * `phx-target` (`:any`)
  * `phx-value-tab` (`:string`)
* `content` - Accepts attributes:

  * `value` (`:string`) (required)
  * `id` (`:string`)
  * `class` (`:string`)

---

*Consult [api-reference.md](api-reference.md) for complete listing*
