Skip to content
Redpanda UI
Esc
↑↓navigate↵open⌘Jpreview
Made by nyxb
Edit on GitHub

Multi Select

Lets the user pick several options from a searchable list opened by a button, with the chosen options shown as independently removable chips beside a native opener button.

Installation

bash
npx shadcn@latest add @redpanda/multi-select
bash
pnpm dlx shadcn@latest add @redpanda/multi-select
bash
yarn dlx shadcn@latest add @redpanda/multi-select
bash
bunx shadcn@latest add @redpanda/multi-select
bash
nubx shadcn@latest add @redpanda/multi-select
bash
aube dlx shadcn@latest add @redpanda/multi-select

Tweaked by malinskibeniamin, multi select component combines regular select, badge, command and tooltip. It lets users see and select multiple items.

When to use

The Multi Select component allows users to select multiple options from a list. Use this decision tree to determine when it’s appropriate:

Usage

tsx
import {  MultiSelect,  MultiSelectContent,  MultiSelectControl,  MultiSelectItem,  MultiSelectList,  MultiSelectTrigger,  MultiSelectValue,} from '@/components/redpanda-ui/multi-select';
tsx
<MultiSelect>  <label htmlFor="framework-choice">Frameworks</label>  <MultiSelectControl className="w-80">    <MultiSelectValue />    <MultiSelectTrigger id="framework-choice" placeholder="Select frameworks" />  </MultiSelectControl>  <MultiSelectContent>    <MultiSelectList>      <MultiSelectItem value="react">React</MultiSelectItem>      <MultiSelectItem value="vue">Vue</MultiSelectItem>      <MultiSelectItem value="angular">Angular</MultiSelectItem>      <MultiSelectItem value="svelte">Svelte</MultiSelectItem>    </MultiSelectList>  </MultiSelectContent></MultiSelect>

Control anatomy and keyboard behavior

MultiSelectControl is the noninteractive field shell and popup anchor. Its selected values and opener are siblings:

text
MultiSelect├─ MultiSelectControl│  ├─ MultiSelectValue → selected chips, each with a removal button│  └─ MultiSelectTrigger → native button that opens the options└─ MultiSelectContent → search and option list

Keep MultiSelectValue outside MultiSelectTrigger. Do not nest interactive content inside the opener. Give the opener a persistent name using an associated <label htmlFor> and id, aria-labelledby, or aria-label. Forward form IDs, descriptions, invalid state, blur handlers, and button refs to MultiSelectTrigger, not the shell. Place FormControl around the trigger only.

  • Enter or Space on the opener opens the popup. Keyboard opening focuses the search input when present; Escape closes it and returns focus to the opener.
  • Each selected chip has a named Remove … button. Removing a chip does not open or close the popup.
  • After an accepted removal, focus moves to the next visible removal action, then the previous one, or the opener when no other visible action remains. Ignored or failed controlled updates do not move focus away from the original action. Synchronous removal callback failures display an error.
  • disabled on MultiSelect disables the opener, removal actions, search, and options. The opener and removal actions use type="button"; they do not submit enclosing forms.
  • maxDisplay limits visible chips; all selections remain in the value. maxItemLength truncates visible text but keeps the full removal name and exposes the full label in a tooltip on the removal action.

Migrating the compound API

Replace the former nested trigger/value structure with the sibling anatomy above. Move field width/layout classes from MultiSelectTrigger to MultiSelectControl, and move placeholder from MultiSelectValue to MultiSelectTrigger.

MultiSelectTrigger now forwards native button attributes/events and an HTMLButtonElement ref instead of rendering a role-button div. It no longer accepts children; its native type="button" is not configurable. Its content and type="button" are owned by the component; there is no render, asChild, or nativeButton={false} escape. MultiSelectValue no longer accepts placeholder. SimpleMultiSelect already builds the new anatomy; existing value/options/width contracts remain available.

Examples

Default

Simple

Form

search by control or load remote data

Input Custom (tag mode)

Allow user to select from input custom tag

Limit Count

limit max select count by maxCount

Limit item display length

limit max display item count with maxDisplay, or limit item display length with maxItemLength

Props

Credits

  • We take our inspiration from Shadcn UI for the select style.
  • We use Nyxb UI for the multi select component functionality.

Recent changes

  • patchv1.2.0Pin shipped dependency floors to the version we develop against. Registry items now declare ranges like `^5.1.9` (the actual installed version) instead of collapsing to `^5.0.0`, so consumers start on the known-tested baseline while caret semantics still allow any compatible release within the same major.#133
  • minorv1.1.0Theme docs refresh, readability pass on semantic foregrounds, and consumer-facing Base UI regression fixes.#121
  • minorv1.0.0Post-Base-UI polish. Public API unchanged.#116
  • majorv1.0.0Migrate every Radix-based primitive to `@base-ui/react@^1.4.0` (Base UI).#114
  • minorv0.3.0Add theme-provider component to the registry with documentation and tests. Includes playground type improvements (export RegistryItem, remove as-const boilerplate) and docs site dark mode border color fix.#109
See full history →

Last updated on

Was this page helpful?