Overview of the Phoenix and LiveView Headless Toolbar Component
The Mishka Chelekom Headless Toolbar
ships zero opinionated styling
- only the semantic markup, full WAI-ARIA
wiring, and roving-focus keyboard navigation over a mix of buttons, links, inputs,
groups and separators. Arrow keys move focus along the
orientation
, looping when
loop
is set, while a focused input keeps its own cursor movement and only hands navigation
back at the text boundaries. Every item is declared through an
:item
slot with its own
class
, so you style it
entirely with your own Tailwind
classes while the accessibility and
behavior keep working underneath.
Base UI Toolbar example (Phoenix headless)
<.toolbar id="baseui-toolbar-hero" class="flex w-150 items-center gap-px border border-neutral-950 bg-white p-px dark:border-white dark:bg-neutral-950" > <:item group="Alignment" group_class="flex" label="Align left" class="flex h-8 min-w-8 items-center justify-center gap-2 border-0 bg-transparent px-3 font-[inherit] text-sm leading-none whitespace-nowrap font-normal text-neutral-950 select-none hover:not-data-[disabled]:bg-neutral-100 active:not-data-[disabled]:not-data-[pressed]:bg-neutral-200 data-[pressed]:bg-neutral-950 data-[pressed]:text-white data-[pressed]:hover:not-data-[disabled]:bg-neutral-950 data-[pressed]:hover:not-data-[disabled]:text-white dark:text-white dark:hover:not-data-[disabled]:bg-neutral-800 dark:active:not-data-[disabled]:not-data-[pressed]:bg-neutral-700 dark:data-[pressed]:bg-white dark:data-[pressed]:text-neutral-950 focus-visible:bg-transparent focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white" > Align Left </:item> <:item group="Alignment" label="Align right" class="flex h-8 min-w-8 items-center justify-center gap-2 border-0 bg-transparent px-3 font-[inherit] text-sm leading-none whitespace-nowrap font-normal text-neutral-950 select-none hover:not-data-[disabled]:bg-neutral-100 active:not-data-[disabled]:not-data-[pressed]:bg-neutral-200 data-[pressed]:bg-neutral-950 data-[pressed]:text-white dark:text-white dark:hover:not-data-[disabled]:bg-neutral-800 dark:active:not-data-[disabled]:not-data-[pressed]:bg-neutral-700 dark:data-[pressed]:bg-white dark:data-[pressed]:text-neutral-950 focus-visible:bg-transparent focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white" > Align Right </:item> <:item type="separator" class="m-1 h-4 w-px bg-neutral-950 dark:bg-white" /> <:item group="Numerical format" group_class="flex" label="Format as currency" class="flex h-8 min-w-8 items-center justify-center gap-2 border-0 bg-transparent font-[inherit] text-sm leading-none whitespace-nowrap font-normal text-neutral-950 select-none hover:not-data-[disabled]:bg-neutral-100 active:not-data-[disabled]:not-data-[pressed]:bg-neutral-200 data-[pressed]:bg-neutral-950 data-[pressed]:text-white dark:text-white dark:hover:not-data-[disabled]:bg-neutral-800 dark:active:not-data-[disabled]:not-data-[pressed]:bg-neutral-700 dark:data-[pressed]:bg-white dark:data-[pressed]:text-neutral-950 focus-visible:bg-transparent focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white" > $ </:item> <:item group="Numerical format" label="Format as percent" class="flex h-8 min-w-8 items-center justify-center gap-2 border-0 bg-transparent font-[inherit] text-sm leading-none whitespace-nowrap font-normal text-neutral-950 select-none hover:not-data-[disabled]:bg-neutral-100 active:not-data-[disabled]:not-data-[pressed]:bg-neutral-200 data-[pressed]:bg-neutral-950 data-[pressed]:text-white dark:text-white dark:hover:not-data-[disabled]:bg-neutral-800 dark:active:not-data-[disabled]:not-data-[pressed]:bg-neutral-700 dark:data-[pressed]:bg-white dark:data-[pressed]:text-neutral-950 focus-visible:bg-transparent focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white" > % </:item> <:item type="separator" class="m-1 h-4 w-px bg-neutral-950 dark:bg-white" /> <:item label="Font family" class="flex h-8 min-w-32 cursor-default items-center justify-between gap-2 border-0 bg-transparent px-2 font-[inherit] text-sm leading-none whitespace-nowrap font-normal text-neutral-950 select-none hover:not-data-[disabled]:bg-neutral-100 active:not-data-[disabled]:not-data-[pressed]:bg-neutral-200 dark:text-white dark:hover:not-data-[disabled]:bg-neutral-800 focus-visible:bg-transparent focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white" > Helvetica <svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor" class="block"> <path d="M11 10H5l3 3.5zm0-4H5l3-3.5z" /> </svg> </:item> <:item type="separator" class="m-1 h-4 w-px bg-neutral-950 dark:bg-white" /> <:item type="link" href="#" class="mr-[0.875rem] ml-auto flex-none self-center font-[inherit] text-sm text-neutral-500 no-underline hover:text-blue-700 dark:text-neutral-400 dark:hover:text-blue-500 focus-visible:outline-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white" > Edited 51m ago </:item> </.toolbar>
Parts & data attributes
Each part carries a stable
data-part
(where applicable) and a structural
chelekom-toolbar__*
class you can target, plus orientation and disabled state reflected as data attributes.
| Part | Element / role | State / ARIA | Purpose |
|---|---|---|---|
| Root | div, role="toolbar" | aria-orientation, aria-disabled, data-orientation, data-disabled | Carries the Toolbar hook; reads orientation/loop/disabled/focusable from data attributes. |
| Button | button | data-orientation, data-disabled, data-focusable | Default item type; a roving-focus toolbar control. |
| Link | a | data-orientation | Item type "link"; participates in the same roving order. |
| Input | input | data-orientation, data-disabled, data-focusable | Item type "input"; keeps its own cursor movement, hands navigation back at the text boundaries. |
| Group | div, role="group" | aria-label, data-orientation, data-disabled | Wraps consecutive items that share the same group label. |
| Separator | div, role="separator" | data-orientation | Item type "separator"; a visual divider, not focusable. |
Accessibility
Follows the
WAI-ARIA Toolbar pattern
: arrow keys move focus along the orientation and loop past the ends when
loop
is set,
Home
/
End
jump to the first / last item, and
Tab
moves focus out of the toolbar entirely. With
focusable_when_disabled
(the default), disabled items stay in the roving order - focusable but inert - so they
remain discoverable.