MultiSelect
A dropdown component that allows users to select multiple options from a list, with support for search, chips, and validation states.
Import
Usage
Examples
Custom chip display
Disable chip display
Inheritance
MultiSelect extends the <Select /> component and inherits all of its props and functionality. This means you can use any Select prop with MultiSelect, including:
size,radius,variant,colorlabel,labelAlign,description,messagestatus,required,isLoading,disabledstartContent,endContent,className, and all native field attributesoptions,placeholder,isSearch,searchPlaceholder,belowListmenuconfiguration for dropdown appearance
Reference: For a complete list of inherited props with detailed descriptions, see the Select documentation.
What MultiSelect adds
MultiSelect extends Select with the following additional features:
| Feature | Description |
|---|---|
| Multi-Selection | Allows selecting multiple options from the list |
| Chip Display | Selected options are displayed as removable chips below the trigger |
| Chip Configuration | Full control over chip appearance via the chip prop |
| Toggle Selection | Clicking an option toggles its selection state |
| Selection Count | Shows the number of selected items in the trigger |
What MultiSelect modifies
| Modification | Description |
|---|---|
value | Array of selected values instead of a single value |
onChange | Receives an array of selected values |
placeholder | Replaced with InputLabel - shows when no items selected |
| Selection Behavior | Toggle selection instead of replacing selection |
What MultiSelect does not inherit
The following Select props are not available on MultiSelect:
| Prop | Reason |
|---|---|
onValueChange | Replaced with onChange which receives an array |
initialValue | Not applicable - use value with array |
placeholder | Replaced with InputLabel |
All other Select props are fully supported. See the Select documentation for the complete list.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
options | SelectMenuOption[] | [] | Array of options to display |
value | (string | number)[] | None | Controlled selected values |
onChange | (values: (string | number)[]) => void | None | Callback when selection changes |
InputLabel | string | "Select Options..." | Label displayed when no items selected |
isSearch | boolean | true | Enable search functionality |
searchPlaceholder | string | "Search..." | Search input placeholder |
searchInputName | string | "multiselect-search" | Search input name attribute |
belowList | ReactNode | None | Content to display below the option list |
disableChipDisplay | boolean | false | Hide the selected chips display area |
chipLabel | string | None | Label above the chips section |
chip | ChipConfig | None | Chip configuration overrides (see below) |
menu | MenuConfig | None | Menu configuration overrides (see below) |
containerClassName | string | None | Extra classes for container |
Chip Configuration
The selected chips appearance is controlled through the chip prop:
| Prop | Type | Default | Description |
|---|---|---|---|
chip.variant | "solid" | "ghost" | "bordered" | "faded" | "underlined" | "solid"* | Visual style of chips |
chip.color | "none" | "primary" | "secondary" | "danger" | "warning" | "success" | "primary"* | Color of chips |
chip.radius | "none" | "xs" | "sm" | "md" | "lg" | "xl" | "full" | "sm"* | Corner rounding of chips |
chip.size | "sm" | "md" | "lg" | "sm"* | Size of chips |
Menu Configuration
The dropdown menu appearance is controlled through the menu prop, which accepts all MenuConfig options:
| Prop | Type | Default | Description |
|---|---|---|---|
menu.radius | Radius | "md"* | Corner rounding of the dropdown menu |
menu.size | Size | "md"* | Size of menu items |
menu.itemVariant | Variant | "ghost"* | Visual style of inactive options |
menu.itemColor | Color | "primary"* | Color of inactive options |
menu.activeItemVariant | Variant | "faded"* | Visual style of selected option |
menu.activeItemColor | Color | "primary"* | Color of selected option |
menu.lockScroll | boolean | false* | Whether to lock body scroll when open |
menu.portal | boolean | true* | Whether to render menu in a portal |
menu.portalTarget | HTMLElement | null | null* | Custom portal target element |
menu.className | string | None | Extra classes for the dropdown menu |
SelectMenuOption
| Prop | Type | Description |
|---|---|---|
label | string | Display text for the option |
value | string | number | Value of the option |
disabled | boolean | Prevents selection of this option |
[key: string] | unknown | Additional custom properties |
Global Configuration
MultiSelect reads defaults from four places, in this order of precedence:
- Instance prop: set directly on
<MultiSelect /> - Component config:
components.multiSelectin yourashee.config - Theme default:
defaultVariant/defaultColor/defaultRadiusin yourashee.config - Built-in fallback: component's internal default values
Component config
Built-in fallbacks
Accessibility
- Renders with proper ARIA roles (
combobox,listbox) - Uses
aria-expandedandaria-haspopupfor state indication - Uses
aria-invalidfor error states - Chips include accessible remove buttons with
aria-label - Supports keyboard navigation and selection
disableditems are not focusable or selectable- Implements
focus-visibleindicators
Portal Behavior
The MultiSelect dropdown menu is rendered in a React portal by default. This means the menu is attached to document.body rather than staying in the component's DOM hierarchy.
Why use a portal?
- Escapes CSS containment: The menu appears above other content even when inside containers with
overflow: hiddenorcontain: layout - Avoids stacking context issues: The menu maintains proper z-index regardless of parent stacking contexts
- Works with any parent: The menu functions correctly regardless of where the MultiSelect is placed in the component tree
- Prevents clipping: The menu is never clipped by parent containers
When to disable the portal
You may want to disable the portal (by setting menu.portal={false}) when:
- You need the menu to stay within a specific container for testing purposes
- You are rendering inside a shadow DOM or iframe where
document.bodyis not appropriate - You have specific layout requirements that depend on the menu remaining in the DOM hierarchy
You can also provide a custom menu.portalTarget to render the menu into a specific container instead of document.body.
Notes
- Controlled Usage: Use
value/onChangefor controlled behavior. - Chip Display: Selected options are displayed as removable chips below the trigger button.
- Search: The search input filters options in real-time. Disable with
isSearch={false}. - Custom Value Handling: The component accepts both controlled (via
value/onChange) and custom chip handlers (chipOptions,handleRemoveChip,handleAddChip). - Below List: The
belowListprop is useful for adding "Add new" buttons or additional controls. - Portal: The dropdown menu is portaled to
document.bodyby default. This can be disabled via themenu.portalprop or component config. - Inheritance: MultiSelect inherits all Select props but modifies the selection behavior for multiple values.