@xsolla/xui-multi-select
v0.174.3
Published
A cross-platform multi-select control that lets users pick multiple options from a dropdown list.
Downloads
14,638
Readme
MultiSelect
A cross-platform multi-select control that lets users pick multiple options from a dropdown list.
Installation
npm install @xsolla/xui-multi-selectImports
import { MultiSelect } from "@xsolla/xui-multi-select";
import type {
MultiSelectProps,
MultiSelectOption,
MultiSelectValue,
MultiSelectVariant,
MultiSelectSize,
MultiSelectState,
} from "@xsolla/xui-multi-select";Quick start
const options = [
{ label: "React", value: "react" },
{ label: "Vue", value: "vue" },
{ label: "Angular", value: "angular" },
];
const [selected, setSelected] = useState<MultiSelectValue>([]);
<MultiSelect
label="Frameworks"
options={options}
value={selected}
onChange={setSelected}
placeholder="Select frameworks"
/>;External panel (B2B grouped select)
When the option list is rendered elsewhere (for example @xsolla/xui-b2b-group-select), set dropdownMenu={false} so the control does not open the built-in list. Wire the same value / onChange to both components; use onTriggerPress to toggle your panel, menuOpen for chevron/open styling, and menuMinWidth (default 540, aligned with GROUP_SELECT_MIN_PANEL_WIDTH) so the field matches the panel width.
import * as React from "react";
import { MultiSelect } from "@xsolla/xui-multi-select";
import {
GroupSelect,
GROUP_SELECT_MIN_PANEL_WIDTH,
type GroupSelectGroup,
} from "@xsolla/xui-b2b-group-select";
const groups: GroupSelectGroup[] = [
/* ... */
];
const flatOptions = groups.flatMap((g) =>
g.items.map((it) => ({ value: it.id, label: it.label }))
);
export default function GroupedFieldShell() {
const [value, setValue] = React.useState<string[]>([]);
const [open, setOpen] = React.useState(false);
return (
<>
<MultiSelect
options={flatOptions}
value={value}
onChange={(v) => setValue(v.map(String))}
placeholder="Select regions"
size="sm"
dropdownMenu={false}
menuOpen={open}
menuMinWidth={GROUP_SELECT_MIN_PANEL_WIDTH}
onTriggerPress={() => setOpen((o) => !o)}
/>
{open && (
<GroupSelect groups={groups} value={value} onChange={setValue} />
)}
</>
);
}Add backdrop, click-outside, and Escape handling in your layout as needed (see Storybook).
API Reference
<MultiSelect>
| Prop | Type | Default | Description |
| ------------------- | --------------------------------------------------------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| testID | string | — | Test ID for testing frameworks. On web this renders as data-testid; on React Native it renders as testID. |
| options | MultiSelectOption[] | — | Available options. |
| value | MultiSelectValue | [] | Selected values. |
| onChange | (values: MultiSelectValue) => void | — | Fired when the selection changes. |
| placeholder | string | 'Select' | Placeholder shown when empty. |
| label | string | — | Label rendered above the control. |
| size | 'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl' | 'md' | Control size. |
| state | 'default' \| 'hover' \| 'focus' \| 'disable' \| 'error' | — | Forced visual state. |
| disabled | boolean | false | Disable the control. |
| errorMessage | string | — | Error message; also marks the control invalid. |
| variant | 'tag' \| 'text' | 'tag' | How selected options are displayed. |
| flexible | boolean | true | When true the control grows with content; otherwise fixed-height. |
| removeTagsButtons | boolean | true | Show a remove button on each tag. |
| extraClear | boolean | false | Show a clear-all button. |
| maxHeight | number | 300 | Maximum dropdown height in pixels. |
| iconLeft | ReactNode | — | Icon rendered on the left of the control. |
| iconRight | ReactNode | — | Icon on the right (overrides the default caret). |
| dropdownMenu | boolean | true | When false, hides the built-in list and disables click-to-open; use with an external picker (e.g. GroupSelect) wired to the same value / onChange. |
| onTriggerPress | () => void | — | When dropdownMenu is false: fired when the user activates the field. Typically toggles the external panel. |
| menuOpen | boolean | false | When dropdownMenu is false: drives chevron direction and layering like the built-in open state. |
| menuMinWidth | number | 540 | When dropdownMenu is false: field min-width in px (matches GroupSelect). Use 0 for no minimum. |
Inherits ThemeOverrideProps (themeMode, themeProductContext).
Types
type MultiSelectValue = (string | number)[];
type MultiSelectVariant = "tag" | "text";
type MultiSelectSize = "xs" | "sm" | "md" | "lg" | "xl";
type MultiSelectState = "default" | "hover" | "focus" | "disable" | "error";
interface MultiSelectOption {
label: ReactNode;
value: string | number;
disabled?: boolean;
}Examples
Sizes
const options = [
{ label: 'React', value: 'react' },
{ label: 'Vue', value: 'vue' },
{ label: 'Angular', value: 'angular' },
];
<MultiSelect options={options} size="xs" placeholder="Extra small" />
<MultiSelect options={options} size="sm" placeholder="Small" />
<MultiSelect options={options} size="md" placeholder="Medium" />
<MultiSelect options={options} size="lg" placeholder="Large" />
<MultiSelect options={options} size="xl" placeholder="Extra large" />Text variant with clear-all
const options = [
{ label: "React", value: "react" },
{ label: "Vue", value: "vue" },
{ label: "Angular", value: "angular" },
];
const [selected, setSelected] = useState<MultiSelectValue>([]);
<MultiSelect
options={options}
value={selected}
onChange={setSelected}
variant="text"
extraClear
/>;Error state
const options = [
{ label: "Design", value: "design" },
{ label: "Engineering", value: "engineering" },
{ label: "Product", value: "product" },
];
const [skills, setSkills] = useState<MultiSelectValue>([]);
<MultiSelect
label="Skills"
options={options}
value={skills}
onChange={setSkills}
errorMessage="Please select at least one skill"
/>;Disabled
const options = [
{ label: "React", value: "react" },
{ label: "Vue", value: "vue" },
{ label: "Angular", value: "angular" },
];
<MultiSelect options={options} value={["react"]} disabled />;Accessibility
- Selection is rendered as a checkbox list inside the dropdown.
- The dropdown is keyboard navigable; selection state is announced to assistive technology.
- An
errorMessagemarks the control as invalid for screen readers.
