Overview of the Phoenix and LiveView Headless Autocomplete Component
The Mishka Chelekom Headless Autocomplete
ships zero opinionated styling
- only the semantic markup, full WAI-ARIA
combobox wiring, typeahead filtering, a roving highlight, and paired-presence state
(
data-open
/
data-closed
/
data-highlighted
/
data-hidden
).
Every part - input, clear, popup,
group
and item
- 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 Autocomplete example (Phoenix headless)
<label class="flex flex-col gap-1 text-sm font-bold text-neutral-950 dark:text-white"> Search tags <.autocomplete id="baseui-autocomplete-hero" placeholder="e.g. feature" input_class="h-8 w-[16rem] border border-neutral-950 bg-white dark:bg-neutral-950 px-2 text-sm font-normal text-neutral-950 placeholder:text-neutral-500 dark:placeholder:text-neutral-400 focus:outline-2 focus:-outline-offset-1 focus:outline-neutral-950 dark:focus:outline-white dark:border-white dark:text-white" popup_class="top-full mt-1 w-[16rem] max-w-[16rem] border border-neutral-950 bg-white text-neutral-950 shadow-[0.25rem_0.25rem_0] shadow-black/12 dark:border-white dark:bg-neutral-950 dark:text-white dark:shadow-none outline-0 overflow-y-auto scroll-py-[0.25rem] py-1 overscroll-contain max-h-[22.5rem]" > <:option value="feature" class="flex cursor-default items-center gap-2 py-2 pr-2 pl-2 text-sm leading-4 outline-hidden select-none data-[highlighted]:relative data-[highlighted]:z-0 data-[highlighted]:text-white data-[highlighted]:before:absolute data-[highlighted]:before:inset-x-0 data-[highlighted]:before:inset-y-0 data-[highlighted]:before:z-[-1] data-[highlighted]:before:bg-neutral-950 dark:data-[highlighted]:text-neutral-950 dark:data-[highlighted]:before:bg-white" > feature </:option> <:option value="bug" class="flex cursor-default items-center gap-2 py-2 pr-2 pl-2 text-sm leading-4 outline-hidden select-none data-[highlighted]:relative data-[highlighted]:z-0 data-[highlighted]:text-white data-[highlighted]:before:absolute data-[highlighted]:before:inset-x-0 data-[highlighted]:before:inset-y-0 data-[highlighted]:before:z-[-1] data-[highlighted]:before:bg-neutral-950 dark:data-[highlighted]:text-neutral-950 dark:data-[highlighted]:before:bg-white" > bug </:option> <:option value="docs" class="flex cursor-default items-center gap-2 py-2 pr-2 pl-2 text-sm leading-4 outline-hidden select-none data-[highlighted]:relative data-[highlighted]:z-0 data-[highlighted]:text-white data-[highlighted]:before:absolute data-[highlighted]:before:inset-x-0 data-[highlighted]:before:inset-y-0 data-[highlighted]:before:z-[-1] data-[highlighted]:before:bg-neutral-950 dark:data-[highlighted]:text-neutral-950 dark:data-[highlighted]:before:bg-white" > docs </:option> <:option value="design" class="flex cursor-default items-center gap-2 py-2 pr-2 pl-2 text-sm leading-4 outline-hidden select-none data-[highlighted]:relative data-[highlighted]:z-0 data-[highlighted]:text-white data-[highlighted]:before:absolute data-[highlighted]:before:inset-x-0 data-[highlighted]:before:inset-y-0 data-[highlighted]:before:z-[-1] data-[highlighted]:before:bg-neutral-950 dark:data-[highlighted]:text-neutral-950 dark:data-[highlighted]:before:bg-white" > design </:option> <:option value="urgent" class="flex cursor-default items-center gap-2 py-2 pr-2 pl-2 text-sm leading-4 outline-hidden select-none data-[highlighted]:relative data-[highlighted]:z-0 data-[highlighted]:text-white data-[highlighted]:before:absolute data-[highlighted]:before:inset-x-0 data-[highlighted]:before:inset-y-0 data-[highlighted]:before:z-[-1] data-[highlighted]:before:bg-neutral-950 dark:data-[highlighted]:text-neutral-950 dark:data-[highlighted]:before:bg-white" > urgent </:option> <:empty> <div class="py-4 pr-4 pl-2 text-sm leading-4 text-neutral-500 dark:text-neutral-400"> No tags found. </div> </:empty> </.autocomplete> </label>
Parts & data attributes
Each part carries a stable
data-part
and a structural
chelekom-autocomplete__*
class you can target, plus paired-presence state for filtering, highlighting, and
open/closed transitions.
| Part | data-part | State / ARIA | Purpose |
|---|---|---|---|
| Input | input | role="combobox", aria-controls, aria-expanded, aria-autocomplete, aria-activedescendant | The text field that filters options as you type. |
| Clear | clear | aria-label, data-hidden |
Opt-in button (
clear
) that empties the input; hidden while it is already empty.
|
| Value | value | - | Hidden form input holding the currently selected value. |
| Status | status | role="status", aria-live="polite" | Live region announcing the result count as you type. |
| Popup | popup | role="listbox", data-open, data-closed | The floating (or inline) list of options. |
| Group / Group label | group / group-label | role="group", aria-labelledby, data-hidden | Wraps consecutive same-group options under a labeled group; hidden when every item inside is filtered out. |
| Item | item | role="option", data-value, data-highlighted, data-hidden, aria-selected | An individual option; hidden when it does not match the query. |
| Empty | empty | data-hidden | Shown when the query matches no options. |
Accessibility
Follows the
WAI-ARIA Combobox pattern
: ArrowDown/ArrowUp opens the popup and moves a roving highlight, Enter selects
the highlighted option, Escape closes the popup, and typing filters the list
(
auto_highlight
highlights the first match so Enter selects it without arrowing down). The live status
region announces the result count to screen readers on every keystroke.