Multi-value dropdown picker built on Headless UI Listbox in multiple mode. Selected values render as removable chips; the option list is fixed (no text filtering).
Reach for MultiSelect when the user picks several values from a fixed list and no text filtering is needed.
MultiCombobox.Select.Use @uxf/ui/multi-select for a controlled component outside a form. Inside a @uxf/form form, use @uxf/form/multi-select instead — it registers the field with react-hook-form and derives isInvalid / helperText from validation. This @uxf/ui component is the controlled primitive the form twin wraps.
import { MultiSelect, MultiSelectOption, MultiSelectValue } from "@uxf/ui/multi-select";
import { useState } from "react";
const options: MultiSelectOption<string>[] = [
{ color: "red", id: "one", label: "Option red" },
{ color: "blue", id: "two", label: "Option blue" },
{ disabled: true, id: "three", label: "Option three" },
];
function Example() {
const [value, setValue] = useState<MultiSelectValue<string>>(null);
return (
<MultiSelect
label="Choose options"
name="example"
onChange={setValue}
options={options}
placeholder="Select..."
value={value}
/>
);
}
value is an array of ids (MultiSelectValue<T> = T[] | null) — not option objects — and onChange receives the new array of ids. Selected chips can be removed with their close button or by pressing Backspace.
Exports: MultiSelect and the types MultiSelectProps, MultiSelectOption, MultiSelectValue, MultiSelectValueId (deprecated alias of SelectableId), MultiSelectTypeRef.
MultiSelectProps<ValueId = SelectableId, Option = MultiSelectOption<ValueId>> extends FormControlProps<ValueId[] | null>. SelectableId is string | number (from @uxf/core/types); MultiSelectOption is { id: ValueId; label: ReactNode; color?: ChipColor; disabled?: boolean }. It is not Clearable — there is no isClearable prop.
| Prop | Type | Default | Description |
|---|---|---|---|
label |
ReactNode |
— | Required. Field label. |
name |
string |
— | Required. Field name (also set as data-name). |
value |
ValueId[] | null |
— | Required. Selected option ids, or null. |
onChange |
(value: ValueId[]) => void |
— | Required. Called with the new array of selected ids. |
options |
Option[] |
— | Required. Selectable options. |
withCheckboxes |
boolean |
false |
Render options as a checkbox list (keeps selected options visible in the list). |
placeholder |
string |
— | Shown when nothing is selected. |
helperText |
ReactNode |
— | Text under the control; styled as an error when isInvalid. |
isDisabled |
boolean |
false |
Disable the control. |
isReadOnly |
boolean |
false |
Prevent changes while staying focusable. |
isInvalid |
boolean |
false |
Invalid styling; sets aria-invalid and styles helperText as an error. |
isRequired |
boolean |
false |
Mark the field required (adds the label indicator). |
hiddenLabel |
boolean |
false |
Visually hide the label (kept for assistive tech). |
keyExtractor |
(option: Option) => string | number |
option.id |
Custom React key for options. |
noOptionsMessage |
string |
localized "No items found" | Empty-list message. |
allOptionsSelectedMessage |
string |
localized "All options are already selected" | Shown when every option is selected. |
iconName |
IconName |
"caretDown" |
Icon for the dropdown arrow. |
size |
InputGroupSize |
"default" |
"small", "default", or "large". |
variant |
InputGroupVariant |
"default" |
Input group variant. |
id |
string |
auto (useId) |
Root id; the error-message id derives from it. |
onBlur / onFocus |
FocusEventHandler<HTMLInputElement> |
— | Focus handlers. |
The component is a forwardRef — the ref points at the trigger <div> (MultiSelectTypeRef = HTMLDivElement). Layout/dropdown props: className, style, form, leftAddon, rightAddon, leftElement, rightElement, inputArrow, dropdownClassName, dropdownMatchesInputWidth, dropdownMaxHeight (default 240), dropdownPlacement (default "bottom"), dropdownStrategy.
Note:
renderOptionis present onMultiSelectPropsbut is not currently wired into the option list — the internal options renderer never forwards it, so options always renderoption.label(or a checkbox whenwithCheckboxes). Custom option rendering has no effect today. (In contrast,MultiComboboxdoes applyrenderOption.)
withCheckboxes renders each option as a checkbox and keeps selected options in the list rather than hiding them.Chip; its color comes from the option's color. Chips are removable unless the control or the option is disabled.small, default, large (via size).isInvalid, isDisabled, isReadOnly).The component composes the input, label, dropdown, form-component, icon, and chip primitives, so import their stylesheets once in your global CSS:
@import url("@uxf/ui/css/icon.css");
@import url("@uxf/ui/css/dropdown.css");
@import url("@uxf/ui/css/label.css");
@import url("@uxf/ui/css/form-component.css");
@import url("@uxf/ui/css/input-basic.css");
@import url("@uxf/ui/css/input.css");
@import url("@uxf/ui/css/chip.css");
@import url("@uxf/ui/css/multi-select.css");
When using withCheckboxes, also import the checkbox stylesheets:
@import url("@uxf/ui/css/checkbox.css");
@import url("@uxf/ui/css/checkbox-input.css");
Also requires the global @uxf/ui token layer, set up once per app — see @uxf/ui setup.