Picker (enhanced select)
A rich selector on top of a plain <select>. The server sends the native control, which works everywhere and submits with the form. On init it is kept as the source of truth and hidden from view; the reader sees a control that opens a searchable list, shows selected values as chips when the select is multiple, respects groups and disabled options, and syncs both ways with the native element. destroy puts the select back exactly as served.
Every select.iv-select is enhanced by default when init or auto.js runs: a bare select gets a generated root that destroy removes again, and data-iv-* options written on the select move to it. Add data-iv-native to the select, or to an ancestor, to keep the native control.
<div class="iv-field" style="max-width: 22rem">
<label class="iv-label" for="p-city">Delivery city</label>
<div class="iv-picker" data-iv-component="picker">
<select class="iv-select" id="p-city" name="city" aria-describedby="p-city-help">
<option value="">Select a city</option>
<option value="bcn">Barcelona</option>
<option value="bio">Bilbao</option>
<option value="cor">Córdoba</option>
<option value="grx">Granada</option>
<option value="mad">Madrid</option>
<option value="agp">Málaga</option>
<option value="svq">Seville</option>
<option value="vlc">Valencia</option>
<option value="zaz" disabled>Zaragoza (no service yet)</option>
</select>
</div>
<p class="iv-field__help iv-u-m-0" id="p-city-help">Sample data, not a real service. Without JavaScript this is the native <code><select></code>; with JavaScript it becomes a searchable listbox. Nine options, so the search field appears on its own.</p>
</div>Multiple values, groups and a limit
With multiple the control shows chips, each with its own remove button; Backspace removes the last one. data-iv-max-items disables the remaining options once the limit is reached. The second example uses the iv-picker--glass variant.
<div class="iv-stack">
<div class="iv-field" style="max-width: 26rem">
<label class="iv-label" for="p-langs">Languages you write in</label>
<div class="iv-picker" data-iv-component="picker" data-iv-max-items="3">
<select class="iv-select" id="p-langs" name="langs" multiple aria-describedby="p-langs-help">
<optgroup label="Romance">
<option value="es" selected>Spanish</option>
<option value="ca">Catalan</option>
<option value="fr">French</option>
<option value="pt">Portuguese</option>
<option value="it">Italian</option>
</optgroup>
<optgroup label="Germanic">
<option value="en" selected>English</option>
<option value="de">German</option>
<option value="nl">Dutch</option>
<option value="sv" disabled>Swedish (editor missing)</option>
</optgroup>
</select>
</div>
<p class="iv-field__help iv-u-m-0" id="p-langs-help">Sample data, not a real profile. Up to three languages: once you pick the third, the rest are announced as unavailable. Chips can be removed one by one, and Backspace removes the last one.</p>
</div>
<div style="max-width: 26rem; padding: var(--iv-space-6); border-radius: var(--iv-radius-lg); background-image: linear-gradient(135deg, var(--iv-color-primary-subtle), var(--iv-color-info-subtle))">
<div class="iv-field">
<label class="iv-label" for="p-tags">Project tags (glass variant)</label>
<div class="iv-picker iv-picker--glass" data-iv-component="picker" data-iv-search="on" data-iv-search-placeholder="Filter tags" data-iv-empty-text="No tag matches" data-iv-close-on-select="true">
<select class="iv-select" id="p-tags" name="tags" multiple aria-describedby="p-tags-help">
<option value="brand">Brand</option>
<option value="design" selected>Design system</option>
<option value="docs">Documentation</option>
<option value="research">Research</option>
<option value="tooling">Tooling</option>
</select>
</div>
<p class="iv-field__help iv-u-m-0" id="p-tags-help">Sample data, not a real backlog. The same control on a frosted surface; this one closes the popover after every pick.</p>
</div>
</div>
</div>// data-iv-component="picker"
{
maxItems: 3,
search: "on",
searchPlaceholder: "Filter tags",
emptyText: "No tag matches",
closeOnSelect: true,
}Options
| Option | Attribute | Default | Effect |
|---|---|---|---|
search | data-iv-search | auto | Search field in the list: auto shows it with more than seven options; on or off force it. |
placeholder | data-iv-placeholder | first empty option | Text shown when nothing is selected. |
searchPlaceholder | data-iv-search-placeholder | Search | Placeholder of the search field. |
emptyText | data-iv-empty-text | No matches | Row shown when the search matches nothing. |
clearable | data-iv-clearable | true | Show a clear button when there is a value. |
closeOnSelect | data-iv-close-on-select | true / false | Close after choosing; defaults to true for single and false for multiple selects. |
maxItems | data-iv-max-items | 0 | Maximum number of selected values in a multiple select; 0 means no limit. |
Methods and events
open(), close(), toggle(), select(value), deselect(value), clear(), destroy(); read value (a string, or an array for multiple), isOpen, native and optionElements. Events on the root element: iv:open/iv:close (cancelable) then iv:opened/iv:closed; iv:change (cancelable, detail.value, added, removed) then iv:changed. The native select also receives input and change, so existing form code keeps working.
Keyboard and assistive technology
On the control: Down, Enter or Space open the list, typing opens and filters when search is on, Backspace removes the last chip. In the list: Up and Down move with wrap-around and skip disabled options, Home and End jump, Enter or Space select (multiple selects toggle without closing), Escape closes and returns focus to the control, Tab closes. The control follows the select-only combobox pattern with a listbox; the highlighted option is exposed through aria-activedescendant, and each chip's remove button has an accessible name.
Without JavaScript
The native select is shown as usual, styled by form.css. Groups, disabled options and multiple selection are all native features, so nothing is lost.
Common mistakes
- Reading the value from the picker instead of the select: the form submits the native element, so read from it or listen to its
change. - Thousands of options: the list is rendered in full. Reduce the data on the server.
- Omitting the
<label for>: the control takes its name from the label.
Class index
Parts and modifiers of this family that the examples above do not show. The full list per stylesheet lives in the reference.
| Class | What it does |
|---|---|
iv-picker__value | Text the closed control shows: the selection or the placeholder. |
iv-picker__placeholder | Modifier of that text while nothing is selected. |
iv-picker__caret | Arrow of the control, drawn with a mask. |
iv-picker__chip-label | Label inside a chip of a multiple picker. |
iv-picker__group-list | List of options inside a group. |