Multi-select
A field that keeps every selection as a removable tag and opens a searchable option list. Options can carry a leading avatar or glyph, a second description line and extra search keywords, and can be grouped under headings — flat and grouped entries may be mixed in the same array.
import { MultiSelect } from "@pestoui/core"Default
Uncontrolled — pass defaultValue to preselect. Backspace on the field peels off the last tag.
- Team chat
Option media & descriptions
leading takes an avatar, a glyph or a colour dot, and the same node is reused verbatim on the tag once the option is picked. description adds a second line on the row — it is wired through aria-describedby rather than folded into the label, because a list where every row announces as “Issue tracker, opens an issue on failure” is worse than useless. keywords add search terms beyond the label and the value.
- Team chat
- Docs
Grouped options
An entry with its own options array becomes a labelled group; a bare option stays loose. The two can be mixed in one list, and loose options keep their order under a single unlabelled heading — so a group can be introduced later without rewriting the array.
- Tech lead
Overflow & sizes
maxDisplay caps the visible tags — the rest collapse into a single “+N” badge.
- Team chat
- 2 more selected: Push, Webhook
- Team chat
- 2 more selected: Push, Webhook
Controlled
Hold the array yourself — onValueChange fires with the complete next selection.
- Team chat
Selected: chat, email
Search, select all & clear
showSelectAll puts Select all and Clear at the top of the list as real rows rather than in a footer — a footer sits outside the listbox, so the arrow keys never reach it. With a query live, Select all means every matching option: the row scores the query with the same filter the list uses, so the two can never disagree about what “matching” means. clearable adds the trailing button that empties the field in one action, and dismissing from either place keeps the list open so several can be dropped in a row. showSearch={false} removes the search box entirely and moves focus onto the list itself.
- Team chat
Capping the selection
maxSelected is a hard ceiling. Once it bites, unpicked rows go disabled while the ones already chosen stay live, so a full field can still be emptied from the list rather than only from the tags. The message under the list is rendered as soon as a cap exists and left empty until it applies — a live region that mounts holding its text is the one screen readers stay silent about.
- Team chat
Disabled options, disabled field & invalid
A single option opts out with disabled; the whole field opts out with the prop of the same name, which also blocks the popover and every tag’s remove button. aria-invalid paints the destructive border and ring — wrap the field in Field and it is wired for you, along with the message id.
Pick at least one channel.
- Team chat
Props
Pesto UI · 117 documented components