XDSMultiSelector@xds/core · MultiSelector
Preview coming soon

Usage

A checkbox dropdown for selecting multiple values from a list. Selected items can display as a count, labels, or badges. Use it for filtering or when presenting a finite set of options where multiple choices are needed.

Best practices

GuidancePractices
DoUse for a moderate, finite set of options where multiple choices are needed.
DoEnable search filtering when the list exceeds ~15 options.
DoEnable select-all when most users will want all or nearly all options selected.
Don'tUse for single-value selection — use Selector instead.
Don'tShow more than ~20 options without enabling search.

Import

ts
import {XDSMultiSelector} from '@xds/core/MultiSelector'

Props

PropTypeDescription
labelrequired
stringLabel text for accessibility.
optionsrequired
XDSMultiSelectorOptionType[]Array of items — strings, objects with value/label/icon/disabled, dividers, or sections.
valuerequired
string[]Currently selected values.
onChangerequired
(value: string[]) => voidCallback fired when the selection changes.
changeAction
(value: string[]) => void | Promise<void>Async action on change. Fires after onChange.
placeholder
string (default: 'Select...')Placeholder text shown when no value is selected.
size
'sm' | 'md' | 'lg' (default: 'md')Size variant for the selector.
triggerDisplay
'count' | 'labels' | 'badges' (default: 'count')How to display selected items in the trigger.
maxBadges
number (default: 3)Maximum badges to show before "+N". Only for triggerDisplay="badges".
hasSelectAll
booleanWhether to show a select-all checkbox.
selectAllLabel
string (default: 'Select all')Label for the select-all checkbox.
hasSearch
booleanWhether to show a search input for filtering options.
searchPlaceholder
string (default: 'Search...')Placeholder text for the search input.
isDisabled
booleanDisables the selector.
isLabelHidden
booleanVisually hides the label while keeping it accessible.
description
stringHelper text displayed below the label.
isOptional
booleanMarks the field as optional.
isRequired
booleanMarks the field as required.
isLoading
booleanShows a loading spinner in the trigger.
status
{type: 'error' | 'warning' | 'success', message?: string}Validation status with an optional message.
children
(option: XDSMultiSelectorOptionData) => ReactNodeCustom render function for each option in the dropdown.
xstyle
StyleXStylesStyleX styles for layout customization. Must be a stylex.create() value.

Sub-components

MultiSelector is a compound component with 1 sub-component.

XDSMultiSelector

Multi-select dropdown with checkboxes for choosing multiple items.
PropTypeDescription
labelrequired
stringLabel text for accessibility.
optionsrequired
XDSMultiSelectorOptionType[]Array of items — strings, objects with value/label/icon/disabled, dividers, or sections.
valuerequired
string[]Currently selected values.
onChangerequired
(value: string[]) => voidCallback fired when the selection changes.
changeAction
(value: string[]) => void | Promise<void>Async action on change. Fires after onChange.
placeholder
string (default: 'Select...')Placeholder text shown when no value is selected.
size
'sm' | 'md' | 'lg' (default: 'md')Size variant for the selector.
triggerDisplay
'count' | 'labels' | 'badges' (default: 'count')How to display selected items in the trigger.
maxBadges
number (default: 3)Maximum badges to show before "+N". Only for triggerDisplay="badges".
hasSelectAll
booleanWhether to show a select-all checkbox.
selectAllLabel
string (default: 'Select all')Label for the select-all checkbox.
hasSearch
booleanWhether to show a search input for filtering options.
searchPlaceholder
string (default: 'Search...')Placeholder text for the search input.
isDisabled
booleanDisables the selector.
isLabelHidden
booleanVisually hides the label while keeping it accessible.
description
stringHelper text displayed below the label.
isOptional
booleanMarks the field as optional.
isRequired
booleanMarks the field as required.
isLoading
booleanShows a loading spinner in the trigger.
status
{type: 'error' | 'warning' | 'success', message?: string}Validation status with an optional message.
children
(option: XDSMultiSelectorOptionData) => ReactNodeCustom render function for each option in the dropdown.
xstyle
StyleXStylesStyleX styles for layout customization. Must be a stylex.create() value.

Examples

Common configurations, variations, and states.
MultiSelector — Column VisibilityColumn visibility toggle with hidden label, search, select-all, and selection count.
tsx
'use client';
import {useState} from 'react';
import {XDSMultiSelector} from '@xds/core/MultiSelector';
import {XDSCenter} from '@xds/core/Center';
const allColumns = [
{value: 'name', label: 'Name'},
{value: 'email', label: 'Email'},
{value: 'role', label: 'Role'},
{value: 'status', label: 'Status'},
{value: 'created', label: 'Created'},
{value: 'updated', label: 'Updated'},
{value: 'actions', label: 'Actions'},
];
export default function MultiSelectorColumnVisibilitySelector() {
const [visible, setVisible] = useState<string[]>([
'name',
'email',
'role',
'status',
]);
return (
<XDSCenter width={300}>
<XDSMultiSelector
label="Columns"
isLabelHidden
options={allColumns}
value={visible}
onChange={setVisible}
hasSelectAll
hasSearch
triggerDisplay="count"
placeholder="Columns"
/>
</XDSCenter>
);
}
MultiSelector — Form CompositionTwo multi-selectors in a form with required/optional states.
tsx
'use client';
import {useState} from 'react';
import {XDSMultiSelector} from '@xds/core/MultiSelector';
import {XDSVStack} from '@xds/core/Layout';
import {XDSCenter} from '@xds/core/Center';
export default function MultiSelectorForm() {
const [columns, setColumns] = useState<string[]>(['name', 'email']);
const [filters, setFilters] = useState<string[]>([]);
return (
<XDSCenter width={300}>
<XDSVStack gap={4}>
<XDSMultiSelector
label="Visible columns"
description="Choose which columns to display in the table"
options={[
{value: 'name', label: 'Name'},
{value: 'email', label: 'Email'},
{value: 'role', label: 'Role'},
{value: 'status', label: 'Status'},
{value: 'created', label: 'Created at'},
]}
value={columns}
onChange={setColumns}
hasSelectAll
isRequired
triggerDisplay="labels"
/>
<XDSMultiSelector
label="Status filter"
description="Filter by status"
options={['Active', 'Inactive', 'Pending', 'Archived']}
value={filters}
onChange={setFilters}
isOptional
triggerDisplay="badges"
placeholder="All statuses"
/>
</XDSVStack>
</XDSCenter>
);
}
MultiSelector — SearchableMulti-select with search filtering and select-all.
tsx
'use client';
import {useState} from 'react';
import {XDSMultiSelector} from '@xds/core/MultiSelector';
import {XDSCenter} from '@xds/core/Center';
const countries = [
'United States',
'United Kingdom',
'Canada',
'Australia',
'Germany',
'France',
'Japan',
'Brazil',
'India',
'Mexico',
];
export default function MultiSelectorSearchableMultiSelector() {
const [value, setValue] = useState<string[]>([]);
return (
<XDSCenter width={300}>
<XDSMultiSelector
label="Countries"
options={countries}
value={value}
onChange={setValue}
hasSearch
hasSelectAll
placeholder="Select countries..."
/>
</XDSCenter>
);
}
MultiSelector — Sectioned PermissionsMulti-select with options grouped into labeled sections.
tsx
'use client';
import {useState} from 'react';
import {XDSMultiSelector} from '@xds/core/MultiSelector';
import {XDSCenter} from '@xds/core/Center';
export default function MultiSelectorSectionedMultiSelector() {
const [value, setValue] = useState<string[]>([]);
return (
<XDSCenter width={300}>
<XDSMultiSelector
label="Permissions"
options={[
{
type: 'section',
title: 'Read',
options: [
{value: 'read_posts', label: 'Read posts'},
{value: 'read_comments', label: 'Read comments'},
{value: 'read_users', label: 'Read users'},
],
},
{
type: 'section',
title: 'Write',
options: [
{value: 'write_posts', label: 'Write posts'},
{value: 'write_comments', label: 'Write comments'},
],
},
]}
value={value}
onChange={setValue}
placeholder="Select permissions..."
/>
</XDSCenter>
);
}

Showcase source

tsx
import {XDSMultiSelector} from '@xds/core/MultiSelector';
export default function MultiSelectorShowcase() {
return (
<div style={{width: 300}}>
<XDSMultiSelector
label="Columns"
isDefaultOpen
options={['Name', 'Email', 'Role', 'Status', 'Created']}
value={[]}
onChange={() => {}}
placeholder="Select columns..."
/>
</div>
);
}