Usage
Options
With simple values:
<.combobox
id="dog-breed-selector"
name="breed"
list_label="Dog breeds"
options={[
"Labrador Retriever",
"German Shepherd",
"Golden Retriever",
"French Bulldog",
"Bulldog"
]}
/>
With label/value pairs:
<.combobox
id="dog-breed-selector"
name="breed"
list_label="Dog breeds"
options={[
{"Labrador Retriever", "labrador"},
{"German Shepherd", "german_shepherd"},
{"Golden Retriever", "golden_retriever"},
{"French Bulldog", "french_bulldog"},
{"Bulldog", "bulldog"}
]}
/>
With descriptions and a disabled option:
<.combobox
id="dog-breed-selector"
name="breed"
list_label="Dog breeds"
options={[
[key: "Labrador Retriever", value: "labrador", description: "Friendly and outgoing"],
[key: "German Shepherd", value: "german_shepherd", description: "Confident and smart"],
[key: "Bulldog", value: "bulldog", description: "Docile and willful", disabled: true]
]}
/>
Label
The component does not render a label by itself, so you must render one
yourself. This is important for accessibility: without it the text input has
no accessible name, and a screen reader announces it as a combobox without
saying what is being chosen.
The usual way is a <label> whose for attribute is the id you passed:
<label for="dog-breed-selector">Breed</label>
<.combobox
id="dog-breed-selector"
name="breed"
list_label="Dog breeds"
options={@breeds}
/>
If the name is already on the page, for example in the form of a heading,
you can set aria-labelledby to the ID of that element instead:
<h2 id="breed-heading">Breed</h2>
<.combobox
id="dog-breed-selector"
name="breed"
list_label="Dog breeds"
aria-labelledby="breed-heading"
options={@breeds}
/>
aria-labelledby and aria-label are global attributes that are set on
the text input, which is the element that needs the label.
By contrast, list_label labels the listbox and the button that opens it.
It describes the list of options, not the field.
In a form
To use the component in a form, you need to pass the id, name, and
value, and add the label, description, and errors.
<.form for={@form} phx-change="validate" phx-submit="save">
<label for="dog-breed-selector">Breed</label>
<.combobox
id="dog-breed-selector"
name={@form[:breed].name}
value={@form[:breed].value}
list_label="Dog breeds"
options={@breeds}
/>
</.form>
The component renders a hidden input with the given name. Its value is the
selected option value, or, if a free text entry is selected, the entered
value.
The text input the user types uses the given name with a _search suffix.
The submitted value is either the label of the selected option or
the current search term. You can use this value to filter options on the
server side, or otherwise ignore it.
With a clear button
If the clearable attribute is set, a clear button is rendered that
unselects the current selection and clears the search term.
<.combobox
id="dog-breed-selector"
name="breed"
list_label="Dog breeds"
clearable
clear_label="Clear breed"
options={@breeds}
/>
Both the toggle button and the clear button have default content that can
be overridden with the :toggle and :clear slots.
<.combobox id="dog-breed-selector" name="breed" list_label="Dog breeds" clearable options={@breeds}>
<:clear><Heroicon.x_mark /></:clear>
<:toggle><Heroicon.chevron_down /></:toggle>
</.combobox>
With free text
If the free_text attribute is set, the user can choose to submit an
entered value that is not among the options.
<.combobox
id="dog-breed-selector"
name="breed"
list_label="Dog breeds"
free_text
free_text_label="Add breed"
options={@breeds}
/>
With options loaded from the server
Set on_search to filter on the server. If set, the hook stops filtering on
the client side, and your handler receives the typed text as the *_search
parameter described above.
<.combobox
id="dog-breed-selector"
name="breed"
list_label="Dog breeds"
options={@breeds}
on_search="search-breeds"
/>
def handle_event("search-breeds", %{"breed_search" => term}, socket) do
{:noreply, assign(socket, breeds: Dogs.search_breeds(term))}
end
Instead of an event name, you can also pass a Phoenix.LiveView.JS command.
Keyboard
Down - open the listbox, or move to the next option. Opening moves to
the selected option, or to the first one if nothing is selected.
Up - open the listbox at the last option, or move to the previous one.
Alt + Down - open the listbox without moving to an option.
Alt + Up - close the listbox, leaving the text as it is.
Enter - select the active option.
Escape - close the listbox and put the display value of the selection
back in the input. With the listbox already closed and the display value
unchanged, clear the selection.
The combobox is a single tab stop. Focus stays on the text input and never
moves into the listbox. The active option is tracked with
aria-activedescendant. The toggle and the clear button are out of the tab
order; keyboard users can use Alt + Down and Alt + Up for the
toggle, and Escape for clearing.
Home, End, Left, Right, Backspace and Delete are not intercepted
and are reserved for the browser's text editing.