Combobox

Searchable select — Popover + Command pattern.

Installation

npm install @aspyn-io/kit @aspyn-io/tokens
// Combobox is a composition — no new import needed:
import { Popover, PopoverTrigger, PopoverContent } from "@aspyn-io/kit";
import { Command, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem } from "@aspyn-io/kit";
import { Button } from "@aspyn-io/kit";

Searchable select

Combobox = Popover + Command + Button. Use it instead of Select when the option list is long enough to need search.

const [open, setOpen] = React.useState(false);
const [value, setValue] = React.useState("");

<Popover open={open} onOpenChange={setOpen}>
  <PopoverTrigger asChild>
    <Button variant="outline" role="combobox" aria-expanded={open} className="w-56 justify-between">
      {value ? centers.find((c) => c.value === value)?.label : "Select center…"}
      <ChevronsUpDownIcon className="opacity-50" />
    </Button>
  </PopoverTrigger>
  <PopoverContent className="w-56 p-0">
    <Command>
      <CommandInput placeholder="Search centers…" />
      <CommandList>
        <CommandEmpty>No center found.</CommandEmpty>
        <CommandGroup>
          {centers.map((center) => (
            <CommandItem key={center.value} value={center.value}
              onSelect={(next) => { setValue(next); setOpen(false); }}>
              {center.label}
            </CommandItem>
          ))}
        </CommandGroup>
      </CommandList>
    </Command>
  </PopoverContent>
</Popover>

Notes

  • This is a pattern, not a package export — scaffold popover.json + command.json from the registry and compose.
  • Set role="combobox" and aria-expanded on the trigger for screen readers.