# xpl-tabs

`xpl-tabs` groups related views into a single surface: users pick a **tab** to show the matching **panel**. It implements the WAI-ARIA tabs pattern with a horizontal tab list, optional full-width layout, and two visual styles—**underline** (`type="tabs"`, default) and **segment** (`type="segment"`, pill controls in a bordered track)—selected with the **`type`** prop. On narrow viewports the heading row is replaced by an `xpl-select` so the same targets and keyboard behavior stay consistent.

The **Tabs** and **Segment control** Storybook entries document this **one component** with different defaults and Figma references. Each page adds variant-specific guidance (when to use, examples, tokens); the sections below describe behavior that is **the same for both** styles.

Pair **`xpl-tab` (slot `heading`)** with **`xpl-tab-panel` (slot `panel`)** and use the same **`target`** string on each pair so selection stays in sync.

## Usage

### Web component (`<xpl-tabs>`)

Minimal group with two tabs: each `xpl-tab` and `xpl-tab-panel` shares a `target` value. Set `value` on `xpl-tabs` to control the selected tab (defaults to the first tab’s `target` if omitted).

```html
<xpl-tabs value="one">
  <xpl-tab slot="heading" target="one">First</xpl-tab>
  <xpl-tab slot="heading" target="two">Second</xpl-tab>
  <xpl-tab-panel slot="panel" target="one">Content for first tab.</xpl-tab-panel>
  <xpl-tab-panel slot="panel" target="two">Content for second tab.</xpl-tab-panel>
</xpl-tabs>
```

Listen for selection changes with the **`tabChange`** event (detail is the selected `target` string):

```html
<xpl-tabs id="demo" value="a">
  <xpl-tab slot="heading" target="a">A</xpl-tab>
  <xpl-tab slot="heading" target="b">B</xpl-tab>
  <xpl-tab-panel slot="panel" target="a">…</xpl-tab-panel>
  <xpl-tab-panel slot="panel" target="b">…</xpl-tab-panel>
</xpl-tabs>
<script>
  document.getElementById('demo').addEventListener('tabChange', (e) => {
    console.log(e.detail); // "a" | "b"
  });
</script>
```

Disable the entire group (headings, mobile select, and segment pills) with **`disabled`** on `xpl-tabs`. Disable individual tabs with **`disabled`** on `xpl-tab`.

### Plain HTML (BEM classes)

When styling with `tabs.css` without the Stencil component, mirror the structure: `xpl-tabs`, `xpl-tabs__headings` with `role="tablist"` and `aria-orientation="horizontal"`, `xpl-tabs__active-bar` for the underline variant (position/size normally set by JS), **`button.xpl-tab__button`** with **`role="tab"`** (not links), and **`xpl-tab-panel`** for panels. For **segment** (`xpl-tabs--segment`), each heading is **`xpl-tab.xpl-tab--segment`** wrapping **`xpl-button`** (not `.xpl-tab__button`). On small viewports, include **`xpl-tabs__mobile-select`** with **`xpl-select`** for parity with the component.

## Accessibility

- Each **`xpl-tabs`** root gets a unique **`data-tabs-instance-id`** (for example `xpl-tg-1`). **`xpl-tab`** and **`xpl-tab-panel`** derive matching DOM **`id`** values from that id plus the shared **`target`** string: the tab control is **`…-tab-<target>`**, the panel is **`…-panel-<target>`** (with `target` sanitized for HTML `id` rules). The tab exposes **`aria-controls`** pointing at the panel id, **`aria-selected`**, and the panel uses **`aria-labelledby`** pointing at the tab id. **Segment (pill) tabs** render **`xpl-button`**; because **`xpl-button`** does not forward **`id`** / **`role`** / **`aria-*`** to its inner `<button>`, **`xpl-tab`** sets those on the native button after render so focus order and **`aria-labelledby`** stay correct (same pattern as underline tabs, different host element).
- The tab list container is **`role="tablist"`** with **`aria-orientation="horizontal"`**. Underline tabs use **`role="tab"`** on the inner `<button>`; panels use **`role="tabpanel"`** on **`xpl-tab-panel`**.
- **Roving tabindex:** only the active tab’s control is in the tab order (`tabindex="0"`); others use `tabindex="-1"` until focused with arrows.
- **Keyboard:** **Arrow Left/Right** (and **Arrow Up/Down** as next/previous), **Home**, and **End** move between enabled tabs; **Enter** and **Space** activate (via `xpl-button` in segment mode). Direction mirrors in **RTL**.
- When **`disabled`** is set on `xpl-tabs`, tab keyboard navigation and selection are suppressed for the group.

Variant-specific Foundation mappings for underline vs. segment live in the **Tabs** and **Segment control** Storybook pages. The **`xpl-select`** mobile row reuses **`xpl-select`** / **`xpl-dropdown`** tokens from those components.

<!-- Auto Generated Below -->


## Properties

| Property    | Attribute    | Description                                                                   | Type                  | Default     |
| ----------- | ------------ | ----------------------------------------------------------------------------- | --------------------- | ----------- |
| `disabled`  | `disabled`   | Disables the whole tab group (headings, mobile select, and segment pills).    | `boolean`             | `false`     |
| `fullWidth` | `full-width` | Whether to make the tabs full width                                           | `boolean`             | `false`     |
| `type`      | `type`       | Visual and layout variant: classic underline tabs or segment (pill) controls. | `"segment" \| "tabs"` | `'tabs'`    |
| `value`     | `value`      | The selected tab target value, defaults to the first tab                      | `string`              | `undefined` |


## Events

| Event       | Description                                                                                                                                                                                                                                                                                     | Type                  |
| ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------- |
| `tabChange` | Emitted when the selected tab changes (click, keyboard, or mobile `xpl-select`). The event `detail` is the selected tab’s `target` string. Always dispatched from this host (including after heading clicks) so `event.target` is consistent for listeners on `xpl-tabs` or bubbling ancestors. | `CustomEvent<string>` |


## Slots

| Slot        | Description                                                                          |
| ----------- | ------------------------------------------------------------------------------------ |
| `"heading"` | The heading for each tab (required, target attribute is required on the xpl-tab)     |
| `"panel"`   | The panel for each tab (required, target attribute is required on the xpl-tab-panel) |


## Dependencies

### Depends on

- [xpl-select](../xpl-select)

### Graph
```mermaid
graph TD;
  xpl-tabs --> xpl-select
  xpl-select --> xpl-tag
  xpl-select --> xpl-icon
  xpl-select --> xpl-dropdown
  xpl-tag --> xpl-icon
  xpl-dropdown --> xpl-dropdown-group
  xpl-dropdown --> xpl-dropdown-option
  xpl-dropdown-group --> xpl-dropdown-group
  xpl-dropdown-group --> xpl-dropdown-option
  xpl-dropdown-group --> xpl-dropdown-heading
  xpl-dropdown-option --> xpl-icon
  style xpl-tabs fill:#f9f,stroke:#333,stroke-width:4px
```

----------------------------------------------

*Built with [StencilJS](https://stenciljs.com/)*
