preskok/ui

Searchable Multi Select

A multi-select component with search functionality inside the popover.

Installation

pnpm dlx @preskok-org/ui@latest add searchable-multi-select

Usage

import { SearchableMultiSelect } from "@/registry/preskok/ui/preskok-ui/searchable-multi-select"
 
const items = [
  { id: "1", label: "React" },
  { id: "2", label: "Vue" },
  { id: "3", label: "Angular" },
  { id: "4", label: "Svelte" },
]
 
export function SearchableMultiSelectDemo() {
  const [selected, setSelected] = useState(new Set())
 
  return (
    <SearchableMultiSelect
      label="Select Frameworks"
      items={items}
      selectedKeys={selected}
      onSelectionChange={setSelected}
      placeholder="Choose frameworks..."
      searchPlaceholder="Search frameworks..."
    />
  )
}

Examples

Basic Usage

The most basic form of the component with default props:

<SearchableMultiSelect
  items={items}
  selectedKeys={selectedKeys}
  onSelectionChange={setSelectedKeys}
/>

With Custom Labels

Use custom functions to extract key and label from your data:

const users = [
  { userId: "1", name: "John Doe", email: "john@example.com" },
  { userId: "2", name: "Jane Smith", email: "jane@example.com" }
]
 
<SearchableMultiSelect
  items={users}
  getKey={(user) => user.userId}
  getLabel={(user) => user.name}
  selectedKeys={selectedKeys}
  onSelectionChange={setSelectedKeys}
/>

With Maximum Selection

Limit the number of items that can be selected:

<SearchableMultiSelect
  items={items}
  selectedKeys={selectedKeys}
  onSelectionChange={setSelectedKeys}
  maxSelection={3}
  placeholder="Select up to 3 items..."
/>

Show Selection Count

Display selection count instead of tags in the trigger:

<SearchableMultiSelect
  items={items}
  selectedKeys={selectedKeys}
  onSelectionChange={setSelectedKeys}
  showSelectedAsMessage={true}
/>

Custom Render

Use a custom render function for list items:

<SearchableMultiSelect
  items={users}
  selectedKeys={selectedKeys}
  onSelectionChange={setSelectedKeys}
>
  {(user) => (
    <div className="flex items-center gap-2">
      <div className="bg-primary text-primary-foreground flex h-8 w-8 items-center justify-center rounded-full text-sm">
        {user.name.charAt(0)}
      </div>
      <div>
        <div className="font-medium">{user.name}</div>
        <div className="text-muted-foreground text-sm">{user.email}</div>
      </div>
    </div>
  )}
</SearchableMultiSelect>

Props

PropTypeDefaultDescription
itemsT[][]Array of items to display in the list
selectedKeysSelectionnew Set()Currently selected keys
onSelectionChange(keys: Selection) => void-Callback when selection changes
selectionMode"single" | "multiple""multiple"Selection mode
placeholderstring"Select items..."Placeholder text for the trigger
searchPlaceholderstring"Search items..."Placeholder text for the search field
getKey(item: T) => Key(item) => item.idFunction to extract key from item
getLabel(item: T) => string(item) => item.labelFunction to extract label from item
maxSelectionnumber-Maximum number of items that can be selected
showSelectedAsMessagebooleanfalseShow selection count instead of tags
emptyMessagestring"No items found"Message to show when no items match search
labelstring-Label for the component
descriptionstring-Description text
errorMessagestring-Error message
childrenReact.ReactNode | ((item: T) => React.ReactNode)-Custom render function for items