Overview of the Phoenix and LiveView Headless Accordion Component
The Mishka Chelekom Headless Accordion
ships zero opinionated styling
- only the semantic markup, full WAI-ARIA APG
wiring, roving tabindex keyboard navigation, and paired-presence state
(
data-open
/
data-closed
).
Every part - item, header, trigger,
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 Accordion example - single open (Phoenix headless)
<.accordion id="baseui-accordion-hero" collapsible heading_level={3} class="flex w-full max-w-80 flex-col border border-neutral-950 text-neutral-950 dark:border-white dark:text-white" > <:trigger_icon> <svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" class="block shrink-0 transition-transform duration-100 ease-[ease-out] group-data-[panel-open]:rotate-45" > <path d="M1.5 8h13M8 14.5v-13" /> </svg> </:trigger_icon> <:item title="What is Base UI?" trigger_class="group flex w-full items-center justify-between gap-4 bg-transparent px-3 py-2 text-left text-sm font-normal text-neutral-950 select-none hover:not-data-[disabled]:bg-neutral-100 focus-visible:relative focus-visible:z-1 focus-visible:outline-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:text-white dark:hover:not-data-[disabled]:bg-neutral-800" content_class="h-[var(--accordion-panel-height)] overflow-hidden text-sm transition-[height] duration-150 ease-[ease-out] data-[ending-style]:h-0 data-[starting-style]:h-0" > <div class="px-3 py-2"> Base UI is a library of high-quality unstyled React components for design systems and web apps. </div> </:item> <:item title="How do I get started?" class="border-t border-neutral-950 dark:border-white" trigger_class="group flex w-full items-center justify-between gap-4 bg-transparent px-3 py-2 text-left text-sm font-normal text-neutral-950 select-none hover:not-data-[disabled]:bg-neutral-100 focus-visible:relative focus-visible:z-1 focus-visible:outline-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:text-white dark:hover:not-data-[disabled]:bg-neutral-800" content_class="h-[var(--accordion-panel-height)] overflow-hidden text-sm transition-[height] duration-150 ease-[ease-out] data-[ending-style]:h-0 data-[starting-style]:h-0" > <div class="px-3 py-2"> Head to the "Quick start" guide in the docs. If you've used unstyled libraries before, you'll feel at home. </div> </:item> <:item title="Can I use it for my project?" class="border-t border-neutral-950 dark:border-white" trigger_class="group flex w-full items-center justify-between gap-4 bg-transparent px-3 py-2 text-left text-sm font-normal text-neutral-950 select-none hover:not-data-[disabled]:bg-neutral-100 focus-visible:relative focus-visible:z-1 focus-visible:outline-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:text-white dark:hover:not-data-[disabled]:bg-neutral-800" content_class="h-[var(--accordion-panel-height)] overflow-hidden text-sm transition-[height] duration-150 ease-[ease-out] data-[ending-style]:h-0 data-[starting-style]:h-0" > <div class="px-3 py-2">Of course! Base UI is free and open source.</div> </:item> </.accordion>
Base UI Accordion example - multiple open (Phoenix headless)
<.accordion id="baseui-accordion-multiple" multiple collapsible heading_level={3} class="flex w-full max-w-80 flex-col border border-neutral-950 text-neutral-950 dark:border-white dark:text-white" > <:trigger_icon> <svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-linecap="square" stroke-linejoin="round" class="block shrink-0 transition-transform duration-100 ease-[ease-out] group-data-[panel-open]:rotate-45" > <path d="M1.5 8h13M8 14.5v-13" /> </svg> </:trigger_icon> <:item title="What is Base UI?" trigger_class="group flex w-full items-center justify-between gap-4 bg-transparent px-3 py-2 text-left text-sm font-normal text-neutral-950 select-none hover:not-data-[disabled]:bg-neutral-100 focus-visible:relative focus-visible:z-1 focus-visible:outline-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:text-white dark:hover:not-data-[disabled]:bg-neutral-800" content_class="h-[var(--accordion-panel-height)] overflow-hidden text-sm transition-[height] duration-150 ease-[ease-out] data-[ending-style]:h-0 data-[starting-style]:h-0" > <div class="px-3 py-2"> Base UI is a library of high-quality unstyled React components for design systems and web apps. </div> </:item> <:item title="How do I get started?" class="border-t border-neutral-950 dark:border-white" trigger_class="group flex w-full items-center justify-between gap-4 bg-transparent px-3 py-2 text-left text-sm font-normal text-neutral-950 select-none hover:not-data-[disabled]:bg-neutral-100 focus-visible:relative focus-visible:z-1 focus-visible:outline-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:text-white dark:hover:not-data-[disabled]:bg-neutral-800" content_class="h-[var(--accordion-panel-height)] overflow-hidden text-sm transition-[height] duration-150 ease-[ease-out] data-[ending-style]:h-0 data-[starting-style]:h-0" > <div class="px-3 py-2"> Head to the "Quick start" guide in the docs. If you've used unstyled libraries before, you'll feel at home. </div> </:item> <:item title="Can I use it for my project?" class="border-t border-neutral-950 dark:border-white" trigger_class="group flex w-full items-center justify-between gap-4 bg-transparent px-3 py-2 text-left text-sm font-normal text-neutral-950 select-none hover:not-data-[disabled]:bg-neutral-100 focus-visible:relative focus-visible:z-1 focus-visible:outline-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white dark:text-white dark:hover:not-data-[disabled]:bg-neutral-800" content_class="h-[var(--accordion-panel-height)] overflow-hidden text-sm transition-[height] duration-150 ease-[ease-out] data-[ending-style]:h-0 data-[starting-style]:h-0" > <div class="px-3 py-2">Of course! Base UI is free and open source.</div> </:item> </.accordion>
Parts & data attributes
Each part carries a stable
data-part
and a structural
chelekom-accordion__*
class you can target, plus paired-presence state for open/closed transitions.
| Part | data-part | State / ARIA | Purpose |
|---|---|---|---|
| Item | item | data-index, data-value, data-open, data-disabled, data-on-open-change | The wrapper for one header/trigger + panel pair. |
| Header | header | h1 - h6, level set by heading_level | The heading element wrapping the trigger button. |
| Trigger | trigger | aria-expanded, aria-controls, aria-disabled, data-index, data-disabled, data-panel-open | The button that opens/closes its panel; roving tabindex. |
| Panel | panel | role="region", aria-labelledby, data-open, data-closed, data-index, data-orientation, data-disabled, data-starting-style, data-ending-style | The disclosure content; closed panels stay mounted with hidden so the client engine can animate them. |
Accessibility
Follows the WAI-ARIA Accordion pattern : each panel toggles with Enter or Space, arrow keys move focus between headers (vertical or horizontal, RTL-aware), Home/End jump to the first/last enabled header, and disabled headers are skipped. Only one trigger sits in the tab order at a time - the rest are reached with the arrow keys.