Flexible data handling, form integration, and powerful new features
Use your own data structure! Specify which properties to use for value, display, and other fields using value_member
and display_value_member.
Auto-detected! Simply pass an array of [key, value]
tuples. Perfect for simple key-value pairs without creating objects.
Use callbacks when you need complex logic to extract values. Callbacks take precedence over members.
getValueCallback, getDisplayValueCallback, getSubtitleCallback
and getDisabledCallback
can't be serialized as HTML attributes — they're assigned to the element by id in the inline script below.
Seamless HTML form integration! Hidden inputs are automatically created and updated. Choose from 3 formats: json, csv, or array.
Use CSV format for traditional comma-separated values. Great for legacy systems.
Use array format to create multiple hidden inputs. Standard HTML array handling with name[].
(submit the form to see captured params)
New properties and methods for easier value access:
getValue() - Returns single value or array depending on modeselectedValue - Get the selected value(s)selectedItem - Get the first selected item objectgetSelected() - Get all selected item objectsLoad options dynamically as users type. Perfect for large datasets, API searches, or real-time filtering.
searchCallback
receives an AbortSignal
as its 2nd argument. Forward it to fetch
so a superseded keystroke cancels the in-flight request. Pair with search_debounce
to also coalesce keystroke bursts. These callbacks are assigned to each element by id in the inline script below.
Crank the delay up, then type quickly — each keystroke fires a request and cancels the previous in-flight one (watch the log below).
search-debounce)
The API call fires only after you pause typing for the debounce window — so a fast burst of keystrokes collapses into a single request. Set it to 0
to fire on every keystroke.
Show informative tooltips when hovering over badges and remove buttons. Perfect for truncated text or additional context.
getBadgeTooltipCallback
(assigned in the inline script) for rich content. Remove-button tooltips show "Remove [item name]"; placement is configurable (top, bottom, left, right).
Show different text in badges vs dropdown options. This example shows full details in dropdown ("John Doe - Senior Developer") with subtitle showing email, but just first names in badges ("John") for maximum space efficiency!
getDisplayValueCallback
drives the dropdown text while getBadgeDisplayCallback
drives the compact badge text — both assigned in the inline script. It falls back to the standard display value when getBadgeDisplayCallback
isn't provided.
Full control over dropdown action buttons! Add Select All, Clear All, and custom actions with dynamic visibility, tooltips, and custom handlers.
'select-all'
/ 'clear-all'
plus custom actions with onClick, dynamic visibility via getIsVisibleCallback, tooltips, and CSS classes. The actionButtons
array is assigned in the inline script below.
Create dependent dropdowns that automatically update! Setting element.options = newArray
triggers automatic re-rendering. Perfect for Organization → Business Unit → Department flows. This card mirrors upstream's pure-JS reactive cascade; a LiveView-driven variant lives in the extras section below.
{
"organization": null,
"businessUnit": null,
"department": null
}
Three coupled multiselects. Selecting an organization sends a change
event through the LV hook, the server fetches the matching business units, then pushes the new options back to the dependent multiselect via push_event(socket, "web_multiselect:update", %{id, options, value}). Same flow from unit → department.
options={@business_units}? The wrapper auto-emits phx-update="ignore"
on the element so morphdom doesn't tear down the component's internally-managed children. That ignore also blocks LV from morphing the data-options
attribute on subsequent renders — so the canonical way to mutate option-list or selection state from the server is through the hook's handleEvent
channel.
—, unit = —
Set search_event="github_search"
on the wrapper. The hook installs a searchCallback
that pushes %{"query" => q, "id" => id}
to the LV; the server fetches GitHub, returns {:reply, %{results: [...]}, socket}, and the reply resolves the promise in the browser.