Packages
mishka_chelekom
0.0.9-beta.4
0.0.10-alpha.5
0.0.10-alpha.4
0.0.10-alpha.3
0.0.10-alpha.2
0.0.10-alpha.1
0.0.9
0.0.9-rc.2
0.0.9-rc.1
0.0.9-beta.5
0.0.9-beta.4
0.0.9-beta.3
0.0.9-beta.2
0.0.9-beta.1
0.0.9-alpha.20
0.0.9-alpha.18
0.0.9-alpha.17
0.0.9-alpha.16
0.0.9-alpha.15
0.0.9-alpha.14
0.0.9-alpha.13
0.0.9-alpha.12
0.0.9-alpha.11
0.0.9-alpha.10
0.0.9-alpha.9
0.0.9-alpha.8
0.0.9-alpha.7
0.0.9-alpha.6
0.0.9-alpha.5
0.0.9-alpha.4
0.0.9-alpha.3
0.0.9-alpha.2
0.0.9-alpha.1
0.0.8
0.0.8-rc.2
0.0.8-rc.1
0.0.8-beta.5
0.0.8-beta.4
0.0.8-beta.3
0.0.8-beta.2
0.0.8-beta.1
0.0.8-alpha.4
0.0.8-alpha.3
0.0.8-alpha.2
0.0.8-alpha.1
0.0.7
0.0.6
0.0.6-alpha.2
0.0.6-alpha.1
0.0.5
0.0.5-beta.2
0.0.5-beta.1
0.0.5-alpha.12
0.0.5-alpha.11
0.0.5-alpha.10
0.0.5-alpha.9
0.0.5-alpha.8
0.0.5-alpha.7
0.0.5-alpha.6
0.0.5-alpha.5
0.0.5-alpha.4
0.0.5-alpha.3
0.0.5-alpha.2
0.0.5-alpha.1
0.0.4
0.0.4-beta.3
0.0.4-beta.2
0.0.4-beta.1
0.0.4-alpha.9
0.0.4-alpha.8
0.0.4-alpha.7
0.0.4-alpha.6
0.0.4-alpha.5
0.0.4-alpha.4
0.0.4-alpha.3
0.0.4-alpha.2
0.0.4-alpha.1
0.0.3
0.0.3-alpha.3
0.0.3-alpha.2
0.0.3-alpha.1
0.0.2
0.0.2-rc.2
0.0.2-rc.1
0.0.2-beta.4
0.0.2-beta.3
0.0.2-beta.2
0.0.2-beta.1
0.0.2-alpha.3
0.0.2-alpha.2
0.0.2-alpha.1
0.0.1
Mishka Chelekom is a fully featured components and UI kit library for Phoenix & Phoenix LiveView
Current section
Files
Jump to
Current section
Files
usage-rules/headless/tabs.md
# tabs (headless)
Headless tablist with roving focus and positionally-matched panels, implementing the [WAI-ARIA APG Tabs pattern](https://www.w3.org/WAI/ARIA/apg/patterns/tabs/) (auto-activation on focus).
## Generate
```bash
mix mishka.ui.gen.headless tabs
```
Generates `lib/<app>_web/components/headless/tabs.ex` exposing the `tabs/1` component (or `<prefix>tabs/1` if a component prefix is configured). Requires the `RovingTabindex` JS hook to be registered (`import RovingTabindex from "./roving_tabindex.js";`).
## Anatomy
Root `<div>` carries `phx-hook="RovingTabindex"`, `data-orientation`, and `data-activate-on-focus`. Parts (from the catalog):
| Part | `data-part` | Element | Role |
| --- | --- | --- | --- |
| tablist | `tablist` | `div` | `tablist` |
| tab | `item` | `button` | `tab` |
| panel | `panel` | `div` | `tabpanel` |
Note: the tab button uses `data-part="item"` (the generic name the `RovingTabindex` engine queries via `[data-part="item"]`), not `data-part="tab"`.
Slots (from the template): `:tab` (required, repeatable — a tab label) and `:panel` (required, repeatable — a panel positionally matched to its tab by index). The first tab/panel pair is selected/open by default.
## ARIA & keyboard
Roles and ARIA wiring (generated automatically):
- `role="tablist"` with `aria-orientation` bound to `@orientation`.
- Each `role="tab"` button: `id="{id}-tab-{i}"`, `aria-controls="{id}-panel-{i}"`, `aria-selected` (`"true"` on index 0 initially), `tabindex` (`0` on the selected tab, `-1` on the rest).
- Each `role="tabpanel"`: `id="{id}-panel-{i}"`, `aria-labelledby="{id}-tab-{i}"`, `tabindex="0"`.
Keyboard (`RovingTabindex`, horizontal default / vertical when `data-orientation="vertical"`):
- Arrow Right/Down → next tab (wraps), Arrow Left/Up → previous tab (wraps); focusing a tab auto-activates it (move + activate).
- Home → first tab, End → last tab.
- Enter / Space → activate the focused tab.
- Items marked `data-disabled` are skipped.
## State
Paired-presence state attributes toggled by the `RovingTabindex` engine on activation:
- Panel: `data-open` (selected) / `data-closed` (not selected) — mutually exclusive, set via `toggleAttribute` keyed off the tab's `aria-controls`.
- Tab: `aria-selected` is updated to `"true"`/`"false"`, and `data-highlighted` is toggled on the active item.
The template seeds the initial state (`data-open={i == 0}` / `data-closed={i != 0}`, `aria-selected={to_string(i == 0)}`); the JS hook maintains it thereafter.
## Example
```heex
<.tabs id="account-tabs" orientation="horizontal">
<:tab>Profile</:tab>
<:tab>Billing</:tab>
<:tab>Notifications</:tab>
<:panel>
<h3>Profile</h3>
<p>Manage your public profile.</p>
</:panel>
<:panel>
<h3>Billing</h3>
<p>Update your payment method.</p>
</:panel>
<:panel>
<h3>Notifications</h3>
<p>Choose what you get notified about.</p>
</:panel>
</.tabs>
```
Attributes: `id` (required), `orientation` (`"horizontal"` default | `"vertical"`), `class` (merged onto the root), and `rest` (global passthrough). The Nth `:tab` is paired with the Nth `:panel` by position.
## Styling
Ships no colors or visual styling. Hook your own CSS onto the `chelekom-tabs*` classes and the `data-*` state:
- `.chelekom-tabs` — root container.
- `.chelekom-tabs__list` — the tablist.
- `.chelekom-tabs__tab` — each tab button (style selected state via `[aria-selected="true"]` and/or `[data-highlighted]`).
- `.chelekom-tabs__panel` — each panel (style `[data-open]` vs `[data-closed]`, e.g. hide closed panels).