MultiSelect
Multi-select picker built on Radix Popover + Checkbox. Sibling to `Select` for cases where consumers need to pick more than one option (filter rows, multi-ta…
Multi-select picker built on Radix Popover + Checkbox. Sibling to <Select> for cases where consumers need to pick more than one option (filter rows, multi-target actions, tag-style inputs). The popover stays open on toggle; Esc / outside-click closes it. Selected values render as removable chips in the trigger, with an optional "clear all" affordance and a +N more overflow chip via maxSelectedDisplay.
Controlled vs uncontrolled is decided by the presence of value (mirrors Radix Select's convention): pass value for controlled, defaultValue for uncontrolled.
import { MultiSelect } from "@tetherto/mdk-react-devkit";| Prop | Status | Type | Default | Description |
|---|---|---|---|---|
options | Required | MultiSelectOption[] | — | — |
value | Optional | string[] | undefined | — | Controlled selected values. Omit to use `defaultValue` for uncontrolled mode. |
defaultValue | Optional | string[] | undefined | — | Initial values for uncontrolled mode. Ignored when `value` is provided. |
onValueChange | Optional | ((next: string[]) => void) | undefined | — | — |
placeholder | Optional | React.ReactNode | — | — |
disabled | Optional | boolean | undefined | — | — |
size | Optional | MultiSelectSize | undefined | — | — |
variant | Optional | MultiSelectVariant | undefined | — | — |
emptyMessage | Optional | React.ReactNode | — | Rendered inside the popover when `options` is empty. |
maxSelectedDisplay | Optional | number | undefined | — | Max number of selected chips rendered in the trigger before collapsing the rest into a "+N more" badge. `undefined` (default) renders every chip. |
className | Optional | string | undefined | — | — |
contentClassName | Optional | string | undefined | — | — |
aria-label | Optional | string | undefined | — | Accessible label - applied to the trigger button. |
id | Optional | string | undefined | — | — |
name | Optional | string | undefined | — | — |
Usage
Pick multiple values from a dropdown. Built on Radix Popover + the core Checkbox so it stays open on toggle - the canonical Radix pattern for multi-select (Radix Select itself is single-select by design).
Use for filter rows (miner type, mining unit, status), multi-target
actions, or any tag-style input. For a single-value picker use <Select>
instead.
Behaviour notes
- The popover stays open after toggling an option so multi-pick is ergonomic without re-opening on every change.
- Clear-all surfaces in the trigger only when
>= 2values are selected. - Per-chip
xbuttons are not in the tab order (the parent trigger handles focus); they remove only that value on click. - Keyboard: Enter / Space on the trigger opens the popover, Arrow Down / Up move focus through rows, Space toggles the focused row without closing, Esc closes and returns focus to the trigger.
Example
/** * Runnable example for MultiSelect. */import { MultiSelect, type MultiSelectOption } from '@tetherto/mdk-react-devkit/primitives'import { useState } from 'react'const MINER_TYPES: MultiSelectOption[] = [ { value: 'miner-am-s19xp', label: 'Antminer S19XP' }, { value: 'miner-wm-m56s', label: 'WhatsMiner M56S' }, { value: 'miner-av-a1346', label: 'Avalon A1346' }, { value: 'miner-demo-m1', label: 'Demo M1' },]export const MultiSelectExample = () => { const [selected, setSelected] = useState<string[]>([]) return ( <MultiSelect options={MINER_TYPES} value={selected} onValueChange={setSelected} placeholder="Filter by miner type" maxSelectedDisplay={2} /> )}