ListMultiPicker
Chooses several values of a list field, offering the vocabulary its schema declares.
It is the shared picker control with rows from the field’s valid values. The set is fixed and read once, so there is no search row unless a caller asks for one, and a chosen value is a plain chip.
Single and multi: ListPicker takes one value.
Install
Section titled “Install”pnpm dlx shadcn@latest add https://sg-widgets.vercel.app/r/react/list-multi-picker.jsonpnpm dlx shadcn-svelte@latest add https://sg-widgets.vercel.app/r/svelte/list-multi-picker.jsonReact
Loading the React demo…
Svelte
Loading the Svelte demo…
| chosen | emitted |
|---|---|
| an unchecked row | the list with that value added at the end |
| a checked row | the list with that value removed |
| the clear control | an empty list |
The offered set is the field’s valid values, minus its hidden values when a project id is given. A value already held that is outside that set keeps a row of its own, labelled with the value.
The control draws a chip per chosen value. What does not fit on the line becomes a +n pill, and a
press on it opens the list.
| prop | type | default | meaning |
|---|---|---|---|
summary | 'chips' | 'ellipsis' | 'count' | 'ellipsis' | What the control shows for the selection. |
max | number | 0 | Chips drawn before the rest becomes +n. 0 lets the row fit what it can. |
value | string[] | [] | The chosen values. Two-way in Svelte. |
onValueChange | (value: string[]) => void | — | Called on every change, with the whole list. |
fieldfrom ListPicker | Pick<FieldSchema, 'displayName' | 'mandatory' | 'validValues' | 'displayValues' | 'hiddenValues'> | null | null | Supplies the valid values, the labels and the hidden values. |
projectIdfrom ListPicker | number | — | Given, the field's hidden values are removed from the list. |
optionsfrom ListPicker | ListOption[] | — | The set on offer, of the caller's own making. Wins over the field. |
showCodefrom ListPicker | boolean | false | Draws the stored string as a row's right-aligned secondary, where it says more than the label. |
secondaryfrom ListPicker | (option) => string | the value | A row's right-aligned value, of the caller's own making. |
subLabelfrom ListPicker | (option) => string | — | The muted line under a row's label. |
class / classNamefrom ListPicker | string | — | Merged after the widget's own classes. |
slot | string | 'list-multi-picker' | The data-slot prefix every part of this picker carries. |
pickerfrom ListPicker | string | 'list' | The data-picker the popup carries. |
searchablefrom ListPicker | boolean | false | Offers a search box, which narrows the set in the browser. |
sizefrom PickerControl | 'sm' | 'md' | 'lg' | 'md' | Control height: 7, 8 and 9. |
disabledfrom ListPicker | boolean | false | Greys the control and takes it out of the tab order. |
readonly | boolean | false | Keeps full contrast and drops the chevron, the popup and the remove controls. |
invalidfrom ListPicker | boolean | false | Sets aria-invalid and the destructive ring. |
clearable | boolean | the field | Offers a control that clears the selection. Unset, it follows the field: a mandatory one is never clearable. |
placeholder | string | 'Select values' | Shown while nothing is chosen. |
searchPlaceholderfrom ListPicker | string | 'Search values…' | Placeholder of the search box. |
openfrom PickerControl | boolean | required | React: whether the popup is showing. |
openfrom PickerControl | boolean | false | Svelte: whether the popup is showing, two-way. |
onOpenChangefrom PickerControl | (open: boolean) => void | required | React: called when the popup opens or closes. |
onOpenChangefrom PickerControl | (open: boolean) => void | — | Svelte: called when the popup opens or closes. |
errorfrom ListPicker | string | null | null | A message from the caller, drawn under the control. |
emptyLabelfrom ListPicker | string | 'No rows' | Shown when the list offers nothing. |
clearLabelfrom PickerControl | string | 'Clear the selection' | |
triggerLabelfrom PickerControl | string | 'Show the options' |
Every other attribute is spread onto the root: id, aria-*, data-*, key handlers and a ref
to the root element.
A row is the row anatomy of the design rules, after its checkbox: the label as the main text and,
with showCode, the stored string right-aligned.
Events
Section titled “Events”| event | payload | when |
|---|---|---|
onErrorChangefrom ListPicker | string | null | The message changed. |
onValueChange fires as soon as a row is checked or unchecked, and with an empty list when the
selection is cleared. onErrorChange fires with null on that same change, so a message the caller
set clears when the field is answered.
onOpenChange fires when the popup opens or closes. Svelte also binds it with bind:open.
| slot | receives | draws |
|---|---|---|
errorMessagefrom ListPicker | the message | The line under the control. |
Keyboard
Section titled “Keyboard”| key | does |
|---|---|
| Space, Enter, ↓from ListPicker | Opens the list |
| ↑ ↓from ListPicker | Move the highlight |
| typingfrom ListPicker | Narrows the list, where the picker is searchable |
| Enter | Checks or unchecks the highlighted row. The list stays open |
| Backspace | Highlights the last chip; a second press removes it |
| Esc | Closes the list and keeps the selection |
| Tabfrom ListPicker | Leaves the control, or reaches the clear control when there is one |
ArrowDown / ArrowUpfrom PickerControl | Moves the highlight, and the list scrolls it into view. |
Enterfrom PickerControl | Takes the highlighted row. A multi picker keeps the popup open. |
Escapefrom PickerControl | Closes the popup and clears the query. On a closed picker it does nothing. |
Backspacefrom PickerControl | In an empty query: takes the caret to the last chip of a multi picker; clears a single one. |
ArrowLeft / ArrowRightfrom PickerControl | On a chip, walks the row. ArrowRight past the last chip returns to the input. |
Deletefrom PickerControl | On a chip, removes it and leaves the caret on its neighbour. |
Tabfrom PickerControl | Leaves the control. |
API behaviour
Section titled “API behaviour”A list field holds one bare string, so several values only appear in a filter, under in and
not_in. A value outside valid_values is a 400 on write and the comparison is case-sensitive,
down to a trailing space, so the schema’s vocabulary is the whole set a picker may offer
(field_types/list).
Hidden values reach the schema only when it is read with a project id, and REST does not enforce them on write, so the subtraction is the client’s (probe 009).