Overview of the Phoenix and LiveView Headless Tabs Component
The Mishka Chelekom Headless Tabs
ships zero opinionated styling
- only the semantic markup, full WAI-ARIA
tablist wiring, roving focus, and an animated indicator that slides and resizes under
the active tab via CSS variables. Every part - tablist, tab,
indicator
and panel
- is addressable through a
*_class
attribute, so you style it entirely with your own Tailwind
classes while the accessibility and behavior keep working underneath.
Base UI Tabs example (Phoenix headless)
Workspace stats and activity.
Milestones and deadlines.
Profile and preferences.
<.tabs id="baseui-tabs-hero" default_value="overview" class="w-full max-w-xs" list_class="relative z-1 -mb-px flex gap-1" indicator_class="absolute top-0 left-0 -z-1 h-full w-(--active-tab-width) translate-x-(--active-tab-left) border-x border-t border-neutral-950 bg-white transition-[translate,width] duration-150 ease-in-out dark:border-white dark:bg-neutral-950" panels_class="grid w-full min-h-32 grid-cols-1 border border-neutral-950 dark:border-white" > <:tab value="overview" class="flex h-[calc(2rem+1px)] items-center justify-center bg-transparent px-2 py-0 font-inherit text-sm font-normal leading-5 break-keep whitespace-nowrap text-neutral-600 outline-none select-none hover:text-neutral-950 focus-visible:outline-2 focus-visible:outline-solid focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-[active]:text-neutral-950 dark:text-neutral-300 dark:hover:text-white dark:data-[active]:text-white" > Overview </:tab> <:tab value="projects" class="flex h-[calc(2rem+1px)] items-center justify-center bg-transparent px-2 py-0 font-inherit text-sm font-normal leading-5 break-keep whitespace-nowrap text-neutral-600 outline-none select-none hover:text-neutral-950 focus-visible:outline-2 focus-visible:outline-solid focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-[active]:text-neutral-950 dark:text-neutral-300 dark:hover:text-white dark:data-[active]:text-white" > Projects </:tab> <:tab value="account" class="flex h-[calc(2rem+1px)] items-center justify-center bg-transparent px-2 py-0 font-inherit text-sm font-normal leading-5 break-keep whitespace-nowrap text-neutral-600 outline-none select-none hover:text-neutral-950 focus-visible:outline-2 focus-visible:outline-solid focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white data-[active]:text-neutral-950 dark:text-neutral-300 dark:hover:text-white dark:data-[active]:text-white" > Account </:tab> <:panel value="overview" class="col-start-1 row-start-1 flex w-full items-center justify-center bg-white p-4 text-center text-sm text-neutral-950 outline-none focus-visible:z-1 focus-visible:outline-2 focus-visible:outline-solid focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:bg-neutral-950 dark:text-white [&[hidden]]:hidden" > <p>Workspace stats and activity.</p> </:panel> <:panel value="projects" class="col-start-1 row-start-1 flex w-full items-center justify-center bg-white p-4 text-center text-sm text-neutral-950 outline-none focus-visible:z-1 focus-visible:outline-2 focus-visible:outline-solid focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:bg-neutral-950 dark:text-white [&[hidden]]:hidden" > <p>Milestones and deadlines.</p> </:panel> <:panel value="account" class="col-start-1 row-start-1 flex w-full items-center justify-center bg-white p-4 text-center text-sm text-neutral-950 outline-none focus-visible:z-1 focus-visible:outline-2 focus-visible:outline-solid focus-visible:-outline-offset-1 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:bg-neutral-950 dark:text-white [&[hidden]]:hidden" > <p>Profile and preferences.</p> </:panel> </.tabs>
Parts & data attributes
Each part carries a stable
data-part
and a structural
chelekom-tabs__*
class you can target, plus state attributes that drive the active/hidden/orientation
styling and the sliding indicator.
| Part | data-part | State / ARIA | Purpose |
|---|---|---|---|
| Root | root | data-orientation, data-activation-direction | Carries the Tabs hook; data-value is the controlled active tab. |
| Tablist | tablist | role="tablist", aria-orientation | Exposes the --active-tab-left/right/top/bottom/width/height CSS variables. |
| Tab | tab | role="tab", aria-selected, aria-controls, data-active, data-disabled | An individual tab button, part of the roving tabindex. |
| Indicator | indicator | data-orientation, data-activation-direction | The animated underline; positions itself from the --active-tab-* vars. |
| Panel | panel | role="tabpanel", aria-labelledby, data-hidden, data-index | The content matched to its tab by value or position. |
Accessibility
Follows the
WAI-ARIA Tabs pattern
: arrow keys move focus and activate along the tablist's
orientation
, and
Home
/
End
jump to the first / last tab. Activation follows focus automatically unless
activate_on_focus
is turned off, in which case activation requires an explicit selection.