Skip to content

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.

Terminal window
pnpm dlx shadcn@latest add https://sg-widgets.vercel.app/r/react/list-multi-picker.json
Terminal window
pnpm dlx shadcn-svelte@latest add https://sg-widgets.vercel.app/r/svelte/list-multi-picker.json
ListMultiPicker: valid values, labels, a project's hidden values removed, a search box, and a mandatory field

React

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.

proptypedefaultmeaning
summary'chips' | 'ellipsis' | 'count''ellipsis'What the control shows for the selection.
maxnumber0Chips drawn before the rest becomes +n. 0 lets the row fit what it can.
valuestring[][]The chosen values. Two-way in Svelte.
onValueChange(value: string[]) => void—Called on every change, with the whole list.
fieldfrom ListPickerPick<FieldSchema, 'displayName' | 'mandatory' | 'validValues' | 'displayValues' | 'hiddenValues'> | nullnullSupplies the valid values, the labels and the hidden values.
projectIdfrom ListPickernumber—Given, the field's hidden values are removed from the list.
optionsfrom ListPickerListOption[]—The set on offer, of the caller's own making. Wins over the field.
showCodefrom ListPickerbooleanfalseDraws the stored string as a row's right-aligned secondary, where it says more than the label.
secondaryfrom ListPicker(option) => stringthe valueA 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 ListPickerstring—Merged after the widget's own classes.
slotstring'list-multi-picker'The data-slot prefix every part of this picker carries.
pickerfrom ListPickerstring'list'The data-picker the popup carries.
searchablefrom ListPickerbooleanfalseOffers a search box, which narrows the set in the browser.
sizefrom PickerControl'sm' | 'md' | 'lg''md'Control height: 7, 8 and 9.
disabledfrom ListPickerbooleanfalseGreys the control and takes it out of the tab order.
readonlybooleanfalseKeeps full contrast and drops the chevron, the popup and the remove controls.
invalidfrom ListPickerbooleanfalseSets aria-invalid and the destructive ring.
clearablebooleanthe fieldOffers a control that clears the selection. Unset, it follows the field: a mandatory one is never clearable.
placeholderstring'Select values'Shown while nothing is chosen.
searchPlaceholderfrom ListPickerstring'Search values…'Placeholder of the search box.
openfrom PickerControlbooleanrequiredReact: whether the popup is showing.
openfrom PickerControlbooleanfalseSvelte: whether the popup is showing, two-way.
onOpenChangefrom PickerControl(open: boolean) => voidrequiredReact: called when the popup opens or closes.
onOpenChangefrom PickerControl(open: boolean) => void—Svelte: called when the popup opens or closes.
errorfrom ListPickerstring | nullnullA message from the caller, drawn under the control.
emptyLabelfrom ListPickerstring'No rows'Shown when the list offers nothing.
clearLabelfrom PickerControlstring'Clear the selection'
triggerLabelfrom PickerControlstring'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.

eventpayloadwhen
onErrorChangefrom ListPickerstring | nullThe 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.

slotreceivesdraws
errorMessagefrom ListPickerthe messageThe line under the control.
keydoes
Space, Enter, ↓from ListPickerOpens the list
↑ ↓from ListPickerMove the highlight
typingfrom ListPickerNarrows the list, where the picker is searchable
EnterChecks or unchecks the highlighted row. The list stays open
BackspaceHighlights the last chip; a second press removes it
EscCloses the list and keeps the selection
Tabfrom ListPickerLeaves the control, or reaches the clear control when there is one
ArrowDown / ArrowUpfrom PickerControlMoves the highlight, and the list scrolls it into view.
Enterfrom PickerControlTakes the highlighted row. A multi picker keeps the popup open.
Escapefrom PickerControlCloses the popup and clears the query. On a closed picker it does nothing.
Backspacefrom PickerControlIn an empty query: takes the caret to the last chip of a multi picker; clears a single one.
ArrowLeft / ArrowRightfrom PickerControlOn a chip, walks the row. ArrowRight past the last chip returns to the input.
Deletefrom PickerControlOn a chip, removes it and leaves the caret on its neighbour.
Tabfrom PickerControlLeaves the control.

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).