Multi-select Filter

A filter chip for toolbars that narrows a list or report to one or more values.

Basic usage

Pass items, the controlled selectedIds, and onChange. With nothing narrowed the chip is a dashed button with label and iconStart. Once the selection narrows the results, the chip shows the label, the first pick with a +N count, and an X that resets the filter. Hover the chip to see every pick.

renderItemStart adds an icon or avatar to each row; renderSelectionIcons stacks the picked items' icons in the chip. MultiSelectSelectionIcons draws that stack for you.

Empty or all selected

By default, selecting every item means no filter, like the Topic chip here. The X returns to that state, and so does unchecking the last row. With everything selected, the footer's Clear all empties the checkboxes without filtering, and the next pick selects only that row.

When the items are only part of the possible values, such as a few statuses, pass allowEmpty. An empty selection is then the cleared state, the chip stays active while anything is picked, and the X clears to []. Short lists can hide the search with showSearch={false} and the per-row only button with showOnlyButton={false}.

Groups

Pass groups instead of items to show headed sections in your order. Without groups, picked rows move to the top each time the menu opens.

Selector style

For a picker that always has a value, pass inactiveTriggerMode="secondary" and showInactiveTriggerChevron so the cleared chip reads as a select. allSelectedTriggerLabel names the full selection, and showSelectionIconsWhenAllSelected keeps the icons in the chip.

Usage

onChange receives the next selection. To handle each action yourself, pass onToggle, onSelectOnly, onSelectAll, and onClearAll; each falls back to onChange when omitted.

For server-side search, pass disableClientFiltering, read the query from onSearchChange, and set searchInputLoading while results load. Put an infinite-scroll sentinel in listFooter. When items is only the loaded page of a larger set, pass allSelectableIds or selectionActive so the chip knows whether the filter is reset.

Inside a dialog, pass withRadixPortal={false} so the menu scrolls.

Data and selection

labelRequired
string

Name of the filter, shown on the chip

items
T[]

Options, each { id, name, triggerName? }. Use either items or groups

groups
MultiSelectFilterGroup<T>[]

Headed sections, each { id, heading?, items, renderItem? }, shown in order

selectedIdsRequired
string[]

Controlled selection

allowEmpty
boolean

Treats an empty selection as the cleared state, so selecting every item still filters

Default: false

allowEmptySelection
boolean

Keeps all selected as the cleared state but lets the last item be unchecked

Default: false

allSelectableIds
string[]

Every selectable id, when items shows only part of them

selectionActive
boolean

Controls whether the chip shows as active, for selections over paginated items

getItemDisabled
(item: T) => boolean

Disables a row so it cannot be toggled

renderItemDisabledTooltip
(item: T) => ReactNode

Tooltip on a disabled row that explains why

Callbacks

onChange
(ids: string[]) => void

Called with the next selection. The handlers below fall back to it

onToggle
(id: string) => void

Called when a row is checked or unchecked

onSelectOnly
(id: string) => void

Called when a row's only button is clicked

onSelectAll
() => void

Called by Select all and by the X when empty is not the cleared state

onClearAll
() => void

Called by Clear all

onSearchChange
(search: string) => void

Called when the query changes

onOpenChange
(open: boolean) => void

Called when the menu opens or closes

Trigger

iconStart
IconValue

Icon on the cleared chip

size
'micro''small''regular''large'

Chip size. Use small in compact tables and menus

Default: regular

inactiveTriggerMode
ButtonMode

Button style of the cleared chip

Default: dashed

showInactiveTriggerChevron
boolean

Shows a chevron on the cleared chip

Default: false

renderSelectionIcons
(selectedItems: T[]) => ReactNode

Icons of the picked items, shown before the chip's label

showSelectionIconsWhenAllSelected
boolean

Also shows the selection icons when every item is selected

Default: false

hideTriggerLabelText
boolean

Shows only the selection icons in the chip; the label stays for screen readers

Default: false

allSelectedTriggerLabel
ReactNode

Chip label when every item is selected. Defaults to label

emptyTriggerLabel
ReactNode

Chip label when nothing is selected. Defaults to label

triggerLabel
ReactNode

Replaces the first-pick and +N preview in the active chip, for example with a skeleton

triggerTooltip
ReactNode

Replaces the hover list of picks. Pass null to hide it

hasNumericLabels
boolean

Separates the first pick from +N with a comma, for labels such as 18-25

Default: false

disabled
boolean

Disables the chip

Default: false

triggerClassName
string

Classes for the center button of the chip

triggerContainerClassName
string

Classes for the clickable part of the chip

Menu

renderItemStart
(item: T) => IconValue

Icon or avatar before each row's label

renderItemLabel
(item: T) => ReactNode

Replaces each row's label

renderItemEnd
(item: T) => IconValue

Content at the end of each row

showSearch
boolean

Shows the search input

Default: true

searchPlaceholder
string

Placeholder of the search input

Default: Search

searchText
string

Controlled query

disableClientFiltering
boolean

Skips the built-in name filter, for server-side search

Default: false

searchInputLoading
boolean

Shows a spinner in the search input

Default: false

noResultsLabel
ReactNode

Shown when search matches no row

Default: No results found.

showOnlyButton
boolean

Shows the only button on row hover

Default: true

itemsCountLabel
(count: number) => ReactNode

Selected count in the footer

Default: count => `${count} items`

hideEmptyCount
boolean

Hides the footer count when nothing is selected

Default: true

hideSelectAllButton
boolean

Hides the footer's Select all and Clear all button

Default: false

hideClearAllButton
boolean

Hides only Clear all

Default: false

hideFooter
boolean

Hides the footer

Default: false

topRow
ReactNode

Content between the search input and the list

bottomRow
ReactNode

Content between the list and the footer

listFooter
ReactNode

Content at the end of the scrolling list, such as a load-more sentinel

footerExtra
ReactNode

Content below the footer

emptyState
ReactNode

Shown in place of the list when there are no items

align
'start''center''end'

Alignment of the menu relative to the chip. Use end at the trailing edge of a toolbar

Default: start

defaultOpen
boolean

Opens the menu on mount

Default: false

withRadixPortal
boolean

Renders the menu in a portal. Set to false inside a dialog

Default: true

className
string

Classes for the outer wrapper