LiveInteractionContracts. Components. Select
(live_interaction_contracts v1.0.0)
Copy Markdown
View Source
Headless, unstyled, patch-safe select — popover (openness) + cursor (aria-activedescendant) + server-owned selection projected into a hidden form input.
Ownership (the decision that keeps this green — see CONTRACT_SELECT.md)
The playbook's provisional table guessed select would be amber ("value is form
state"). This component resolves that by construction: the selected value never
lives in browser editing state at all. Selection is a lossless client→server
event (on_value_change); the server re-renders the trigger label, the hidden
<input value=...>, and aria-selected — all server-owned constants, patch-safe
by construction. Axis A: green (open = top layer; cursor = one-frame client;
value = server). Axis B: protected-reflection (aria-expanded,
aria-activedescendant, data-highlighted).
Usage
<.select id="fruit" name="fruit" value={@fruit} on_value_change="fruit_changed">
<:trigger>{@labels[@fruit] || "Pick a fruit"}</:trigger>
<:option :for={{id, label} <- @options} id={id}>{label}</:option>
</.select>The caller renders the trigger content (it knows the label for the current
value); the component wires everything else from @id.
Summary
Functions
Attributes
id(:string) (required) - stable id; all wiring is derived from it.value(:string) - server-owned selected option id. Defaults tonil.name(:string) - if set, renders a hidden <input name=... value=...> for form integration. Defaults tonil.on_value_change(:string) - LiveView event pushed with %{id: option_id} when the user selects (lossless). Defaults tonil.mode(:string) - "auto" = native light-dismiss; "manual" = explicit dismiss only. Defaults to"auto". Must be one of"auto", or"manual".placement(:string) - optional zero-JS anchored positioning (CSS Anchor Positioning; see reports/POSITIONING_SPIKE_REPORT.md). Server-owned static style attrs; flips at the viewport edge; follows the anchor through patches/scroll as plain layout. Older engines show it unanchored (documented version floor; no JS fallback). Do not combine with a customstyleon the trigger or listbox element.Defaults to
nil. Must be one ofnil,"bottom", or"top".Global attributes are accepted. extra attrs on the listbox element.
Slots
trigger(required) - trigger content; render the current label here.item(required) - Accepts attributes:id(:string) (required) - stable logical id for this option.