MultiSelect
Usage
MultiSelect component allows user to pick any amount of option from the given data
:
A bare minimum example:
const data = [{ value: 'react', label: 'React' },{ value: 'ng', label: 'Angular' },{ value: 'svelte', label: 'Svelte' },{ value: 'vue', label: 'Vue' },{ value: 'riot', label: 'Riot' },{ value: 'next', label: 'Next.js' },{ value: 'blitz', label: 'Blitz.js' },];function Demo() {return (<MultiSelectdata={data}label="Your favorite frameworks/libraries"placeholder="Pick all that you like"/>);}
Controlled
import { useState } from 'react';import { MultiSelect } from '@mantine/core';function Demo() {const [value, setValue] = useState([]);return <MultiSelect value={value} onChange={setValue} />;}
Note that MultiSelect value should always be an array of either string or null:
// Incorrect, will have bugs<MultiSelect data={[{ value: 1, label: '1' }]} value={[1]} />// Correct, works as expected<MultiSelect data={[{ value: '1', label: '1' }]} value={['1']} />
Data prop
MultiSelect support two different data formats:
- An array of strings – use when you do not need to customize item component or display
label
different thanvalue
- An array of objects with required
value
andlabel
properties and any other additional properties
// Data as an array of strings, will be mapped to// [// { value: 'React', label: 'React' },// { value: 'Angular', label: 'Angular' },// { value: 'Svelte', label: 'Svelte' },// { value: 'Vue', label: 'Vue' },// ]<MultiSelect data={['React', 'Angular', 'Svelte', 'Vue']} />// Data as an array of objects:// Minimal example (same as first example above)<MultiSelect data={[{ value: 'React', label: 'React' },{ value: 'Angular', label: 'Angular' },{ value: 'Svelte', label: 'Svelte' },{ value: 'Vue', label: 'Vue' },]} />// Additional data properties for custom item component (see documentation below)<MultiSelectvalueComponent={({ value, label, image, name }) => /* Your custom value component with data properties */}itemComponent={({ value, label, image, name }) => /* Your custom item component with data properties */}data={[{value: 'bob@handsome.inc',label: 'bob@handsome.inc',image: 'image-link',name: 'Bob Handsome',},{value: 'bill@outlook.com',label: 'bill@outlook.com',image: 'image-link',name: 'Bill Rataconda',},{value: 'amy@wong.cn',label: 'amy@wong.cn',image: 'image-link',name: 'Amy Wong',},]}/>
Searchable
Set searchable
prop to enable search in select and nothingFound
prop to provide label that will be shown when no options were found:
<MultiSelectdata={data}label="Your favorite frameworks/libraries"placeholder="Pick all that you like"searchablenothingFound="Nothing found"/>
Clearable
Set clearable
prop to enable clearing all values at once.
When prop is true and at least value is selected clear button will replace chevron in right section:
<MultiSelectdata={data}label="Your favorite frameworks/libraries"placeholder="Pick all that you like"defaultValue={['react', 'next']}clearButtonLabel="Clear selection"clearable/>
Large data set
When dropdown height is exceeded dropdown becomes scrollable, to change max-height set maxDropdownHeight
prop with value in px:
const data = Array(50).fill(0).map((_, index) => `Item ${index}`);<MultiSelectdata={data}label="Large data set"placeholder="Scroll to see all options"maxDropdownHeight={160}/>
Custom item component
You can change select item component and filtering logic that is used in search. To do so you will need to:
- Add extra props to
data
objects - Create
filter
function which determines whether item should be added to the search results - Provide
itemComponent
andvalueComponent
which will consumedata
objects
// Minimum data used in previous examples[{ value: 'react', label: 'React' },{ value: 'ng', label: 'Angular' },{ value: 'svelte', label: 'Svelte' },{ value: 'vue', label: 'Vue' },];
You can add any other fields to your data:
[{value: 'bob@handsome.inc',image: 'image-link',label: 'bob@handsome.inc',name: 'Bob Handsome',},{value: 'bill@outlook.com',image: 'image-link',label: 'bill@outlook.com',name: 'Bill Rataconda',},{ value: 'amy@wong.cn', image: 'image-link', label: 'amy@wong.cn', name: 'Amy Wong' },];
Based on this data shape you can create custom filter
function and itemComponent
:
import { Group, Avatar, Text, MultiSelect } from '@mantine/core';const data = [{ value: 'bob@handsome.inc', image: 'image-link', label: 'bob@handsome.inc', name: 'Bob Handsome' },{ value: 'bill@outlook.com', image: 'image-link', label: 'bill@outlook.com', name: 'Bill Rataconda' },{ value: 'amy@wong.cn', image: 'image-link', label: 'amy@wong.cn', name: 'Amy Wong' },];function SelectItem({ image, label, name, ...others }) {return (<div {...others}><Group style={{ cursor: 'pointer' }}><Avatar src={image} radius="xl" /><div><Text>{name}</Text><Text size="xs" color="blue">{label}</Text></div></Group></div>);}function Demo() {return (<MultiSelectlabel="Choose employees of the month"placeholder="Pick all you like"itemComponent={SelectItem}data={data}searchablenothingFound="Nobody here"filter={(value, selected, item) =>!selected &&(item.name.toLowerCase().includes(value.toLowerCase().trim()) ||item.label.toLowerCase().includes(value.toLowerCase().trim()))}/>);}
Custom label component
Apart from itemComponent
you can customize appearance of label by providing labelComponent
:
import Flag from 'react-flagpack';import { CloseButton, MultiSelect } from '@mantine/core';function Value({ value, label, onRemove, themeOverride, classNames, ...others }) {const theme = useMantineTheme();return (<div {...others}><divstyle={{display: 'flex',cursor: 'default',alignItems: 'center',border: `1px solid ${theme.colors.gray[4]}`,paddingLeft: 10,borderRadius: 4,}}><div style={{ marginRight: 10 }}><Flag code={value} size="S" /></div><div style={{ lineHeight: 1, fontSize: 12 }}>{label}</div><CloseButton onClick={onRemove} variant="transparent" size={22} iconSize={14} /></div></div>);}function Item({ label, value, elementRef, ...others }) {return (<div ref={elementRef} {...others}><div style={{ display: 'flex' }}><div style={{ marginRight: 10 }}><Flag code={value} size="S" /></div><div>{label}</div></div></div>);}export function CountriesSelect() {return (<MultiSelectdata={countriesData}limit={20}valueComponent={Value}itemComponent={Item}searchabledefaultValue={['US', 'DE']}placeholder="Pick countries"label="Which countries you visited last year?"/>);}
Performance
If you have a large data set (> 100 items) you will have to optimize items rendering.
The best strategy is to use searchable
option with limit
:
// Only 20 items are rendered at a time// See countries list example above<MultiSelect searchable limit={20} />
Animations
By default dropdown animations are turned off to increase responsiveness. You can enable them by setting optional props:
transition
– premade transition name or custom transition styles object, see Transition component for all available optionstransitionDuration
– transition duration in ms, defaults to 0transitionTimingFunction
– defaults totheme.transitionTimingFunction
<MultiSelecttransitionDuration={150}transition="pop-top-left"transitionTimingFunction="ease"/>
With icon
You can use any React node as icon:
<MultiSelect icon={<HashIcon />} />
Invalid state and error
// Error as boolean – red border color<MultiSelect error />// Error as React node – red border color and message below input<MultiSelect error="Pick at least one item" />
Disabled state
In disabled state:
- options to remove, add or search is disabled
- input cannot be cleared with clear button
- cursor is changed to
not-allowed
<MultiSelect disabled />
Right section
You can replace icon in right section with rightSection
prop.
Note that in this case clearable
option will not work and will need to handle it yourself:
<MultiSelect rightSection={<ChevronDownIcon />} />
Input props
Component supports all props from Input and InputWrapper components:
<MultiSelectplaceholder="Pick all you like"label="Your favorite frameworks/libraries"requireddata={['React', 'Angular', 'Svelte', 'Vue']}/>
Get element ref
You can get input ref by passing elementRef
prop to Select component:
import { useRef } from 'react';import { MultiSelect } from '@mantine/core';function Demo() {const ref = useRef(null);return <MultiSelect elementRef={ref} />;}
Server side rendering
Component uses use-id hook to generate unique ids and aria- attributes,
provide static id
prop to prevent props mismatch:
<MultiSelect /> // -> random id generated both on client and server, props mismatch warning<MultiSelect id="my-select" /> // -> id is static, no mismatches
Accessibility
Provide aria-label
in case you use component without label for screen reader support:
<MultiSelect label="My select" />; // -> ok, select and label is connected<MultiSelect />; // not ok, select is not labeled<MultiSelect aria-label="My select" />; // -> ok, label is not visible but will be announced by screen reader
If you use clearable
option set clearButtonLabel
:
<MultiSelect clearable clearButtonLabel="Clear select field" />