{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "combobox",
  "type": "registry:ui",
  "title": "Combobox",
  "description": "A filterable input bound to a listbox popup, built on Base UI Combobox with seam depth motion.",
  "dependencies": [
    "@base-ui/react",
    "motion",
    "lucide-react"
  ],
  "registryDependencies": [
    "https://seamui.dev/r/utils.json",
    "https://seamui.dev/r/motion.json",
    "https://seamui.dev/r/button.json"
  ],
  "files": [
    {
      "path": "registry/seam/ui/combobox.tsx",
      "content": "\"use client\"\n\nimport type * as React from \"react\"\nimport { Combobox as BaseCombobox } from \"@base-ui/react/combobox\"\nimport { Check, ChevronsUpDown, Search, X } from \"lucide-react\"\n\nimport { cn } from \"@/lib/utils\"\nimport { condense } from \"@/lib/motion\"\nimport { buttonVariants } from \"./button\"\n\n/**\n * Combobox — a filterable input bound to a listbox popup. Built on Base UI's\n * Combobox (which owns filtering, keyboard nav, and selection); seamui styles\n * it as a debossed entry field opening an overlay-depth popup of embossed\n * items. See the seamui design language: type *into* the well, pick a raised key.\n *\n * Aliased directly so the generic `<Value, Multiple>` signature (and the\n * `items` / `value` / `multiple` inference it drives) passes through intact.\n */\nconst Combobox = BaseCombobox.Root\n\n/**\n * The debossed text field. Shows a leading search icon, a trailing chevron,\n * and a Clear button once there's a value to clear.\n */\nfunction ComboboxInput({\n  className,\n  placeholder,\n  showClear = true,\n  ...props\n}: React.ComponentProps<typeof BaseCombobox.Input> & {\n  showClear?: boolean\n}) {\n  return (\n    <div className=\"relative w-full\">\n      <Search className=\"text-muted-foreground pointer-events-none absolute left-3 top-1/2 size-4 -translate-y-1/2\" />\n      <BaseCombobox.Input\n        data-slot=\"combobox-input\"\n        placeholder={placeholder}\n        className={cn(\n          // debossed — the field is carved into the surface (inset well shadow).\n          \"flex h-10 w-full min-w-0 rounded-md squircle border border-border/60 bg-muted pl-9 pr-16 py-1 text-sm shadow-well outline-none\",\n          \"placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground\",\n          \"focus-visible:ring-2 focus-visible:ring-ring/50 focus-visible:border-ring\",\n          \"aria-invalid:border-destructive aria-invalid:ring-2 aria-invalid:ring-destructive/30\",\n          \"disabled:pointer-events-none disabled:opacity-50\",\n          className\n        )}\n        {...props}\n      />\n      <div className=\"absolute right-2 top-1/2 flex -translate-y-1/2 items-center gap-0.5\">\n        {showClear && (\n          <BaseCombobox.Clear\n            data-slot=\"combobox-clear\"\n            className={cn(\n              buttonVariants({ variant: \"ghost\", size: \"icon\" }),\n              \"text-muted-foreground size-6 rounded-md\"\n            )}\n            aria-label=\"Clear\"\n          >\n            <X className=\"size-4\" />\n          </BaseCombobox.Clear>\n        )}\n        <BaseCombobox.Icon\n          data-slot=\"combobox-icon\"\n          className=\"text-muted-foreground pointer-events-none flex size-6 items-center justify-center\"\n        >\n          <ChevronsUpDown className=\"size-4\" />\n        </BaseCombobox.Icon>\n      </div>\n    </div>\n  )\n}\n\n/** Portal + Positioner + Popup — the floating list, with overlay-depth motion. */\nfunction ComboboxContent({\n  className,\n  children,\n  sideOffset = 6,\n  ...props\n}: React.ComponentProps<typeof BaseCombobox.Popup> & { sideOffset?: number }) {\n  return (\n    <BaseCombobox.Portal>\n      <BaseCombobox.Positioner sideOffset={sideOffset} className=\"z-50\">\n        <BaseCombobox.Popup\n          data-slot=\"combobox-content\"\n          className={cn(\n            \"bg-popover text-popover-foreground z-50 max-h-[min(24rem,var(--available-height))] w-[var(--anchor-width)] overflow-y-auto overscroll-contain rounded-lg squircle border p-1 shadow-overlay outline-none\",\n            condense.surface,\n            className\n          )}\n          {...props}\n        >\n          {children}\n        </BaseCombobox.Popup>\n      </BaseCombobox.Positioner>\n    </BaseCombobox.Portal>\n  )\n}\n\n/**\n * The list. Pass a render function as the child to map over filtered items:\n * `<ComboboxList>{(item) => <ComboboxItem value={item}>{item.label}</ComboboxItem>}</ComboboxList>`\n */\nfunction ComboboxList({\n  className,\n  ...props\n}: React.ComponentProps<typeof BaseCombobox.List>) {\n  return (\n    <BaseCombobox.List\n      data-slot=\"combobox-list\"\n      className={cn(\"outline-none\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction ComboboxItem({\n  className,\n  children,\n  ...props\n}: React.ComponentProps<typeof BaseCombobox.Item>) {\n  return (\n    <BaseCombobox.Item\n      data-slot=\"combobox-item\"\n      className={cn(\n        \"relative flex cursor-default select-none items-center gap-2 rounded-md squircle py-1.5 pl-2 pr-8 text-sm outline-none\",\n        \"data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground\",\n        \"data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n        className\n      )}\n      {...props}\n    >\n      {children}\n      <BaseCombobox.ItemIndicator className=\"absolute right-2 flex items-center\">\n        <Check className=\"size-4\" />\n      </BaseCombobox.ItemIndicator>\n    </BaseCombobox.Item>\n  )\n}\n\n/** Shown only when the filter yields no matches. */\nfunction ComboboxEmpty({\n  className,\n  ...props\n}: React.ComponentProps<typeof BaseCombobox.Empty>) {\n  return (\n    <BaseCombobox.Empty\n      data-slot=\"combobox-empty\"\n      // Base UI keeps this element mounted (for screen-reader announcements)\n      // and only renders children when the list is actually empty. `empty:`\n      // collapses its padding to zero height while there are matches, so it\n      // doesn't leave a gap at the top of the popup.\n      className={cn(\n        \"text-muted-foreground py-6 text-center text-sm empty:py-0\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nfunction ComboboxGroup(props: React.ComponentProps<typeof BaseCombobox.Group>) {\n  return <BaseCombobox.Group data-slot=\"combobox-group\" {...props} />\n}\n\n/** Renders the filtered items within a group. See the Groups example. */\nconst ComboboxCollection = BaseCombobox.Collection\n\nfunction ComboboxGroupLabel({\n  className,\n  ...props\n}: React.ComponentProps<typeof BaseCombobox.GroupLabel>) {\n  return (\n    <BaseCombobox.GroupLabel\n      data-slot=\"combobox-group-label\"\n      className={cn(\n        \"px-2 py-1.5 text-xs font-medium text-muted-foreground\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\n// Base UI's Combobox has no Separator part, so this is a plain divider.\nfunction ComboboxSeparator({\n  className,\n  ...props\n}: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"combobox-separator\"\n      role=\"separator\"\n      className={cn(\"bg-border -mx-1 my-1 h-px\", className)}\n      {...props}\n    />\n  )\n}\n\n/* ── Multi-select (chips) ────────────────────────────────────────────────\n   For `multiple` comboboxes: a debossed well that wraps selected values as\n   embossed chips alongside the input. Compose as\n   <ComboboxChips>\n     <ComboboxValue>{(items) => items.map((i) => <ComboboxChip …/>)}</ComboboxValue>\n     <ComboboxChipsInput placeholder=\"…\" />\n   </ComboboxChips>\n*/\n\n/**\n * The debossed well that holds chips + the input in multi-select mode.\n * Wrapped in Base UI's InputGroup so the popup anchors to (and matches the\n * width of) the whole well — not the bare input, which would otherwise pin\n * the dropdown to the caret and squeeze it to the input's width.\n */\nfunction ComboboxChips({\n  className,\n  ...props\n}: React.ComponentProps<typeof BaseCombobox.Chips>) {\n  return (\n    <BaseCombobox.InputGroup className=\"w-full\">\n      <BaseCombobox.Chips\n        data-slot=\"combobox-chips\"\n        className={cn(\n          \"flex min-h-10 w-full flex-wrap items-center gap-1.5 rounded-md squircle border border-border/60 bg-muted px-2 py-1.5 text-sm shadow-well outline-none\",\n          \"focus-within:ring-2 focus-within:ring-ring/50 focus-within:border-ring\",\n          \"has-aria-invalid:border-destructive has-aria-invalid:ring-2 has-aria-invalid:ring-destructive/30\",\n          className\n        )}\n        {...props}\n      />\n    </BaseCombobox.InputGroup>\n  )\n}\n\n/** Reads the selected value(s); pass a render function to map them to chips. */\nconst ComboboxValue = BaseCombobox.Value\n\n/** An embossed pill representing one selected value. */\nfunction ComboboxChip({\n  className,\n  children,\n  ...props\n}: React.ComponentProps<typeof BaseCombobox.Chip>) {\n  return (\n    <BaseCombobox.Chip\n      data-slot=\"combobox-chip\"\n      className={cn(\n        \"bg-secondary text-secondary-foreground shadow-resting flex items-center gap-1 rounded-md squircle py-0.5 pl-2 pr-1 text-xs font-medium outline-none\",\n        \"data-[highlighted]:ring-2 data-[highlighted]:ring-ring/50\",\n        className\n      )}\n      {...props}\n    >\n      {children}\n    </BaseCombobox.Chip>\n  )\n}\n\nfunction ComboboxChipRemove({\n  className,\n  ...props\n}: React.ComponentProps<typeof BaseCombobox.ChipRemove>) {\n  return (\n    <BaseCombobox.ChipRemove\n      data-slot=\"combobox-chip-remove\"\n      className={cn(\n        buttonVariants({ variant: \"ghost\", size: \"icon\" }),\n        \"text-muted-foreground size-4 rounded-sm\",\n        className\n      )}\n      aria-label=\"Remove\"\n      {...props}\n    >\n      <X className=\"size-3\" />\n    </BaseCombobox.ChipRemove>\n  )\n}\n\n/** A bare input sized to sit inside the chips well (no icons/affordances). */\nfunction ComboboxChipsInput({\n  className,\n  ...props\n}: React.ComponentProps<typeof BaseCombobox.Input>) {\n  return (\n    <BaseCombobox.Input\n      data-slot=\"combobox-chips-input\"\n      className={cn(\n        \"placeholder:text-muted-foreground min-w-16 flex-1 bg-transparent outline-none\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nexport {\n  Combobox,\n  ComboboxInput,\n  ComboboxContent,\n  ComboboxList,\n  ComboboxItem,\n  ComboboxEmpty,\n  ComboboxGroup,\n  ComboboxGroupLabel,\n  ComboboxCollection,\n  ComboboxSeparator,\n  ComboboxChips,\n  ComboboxChip,\n  ComboboxChipRemove,\n  ComboboxChipsInput,\n  ComboboxValue,\n}\n",
      "type": "registry:ui",
      "target": "components/ui/combobox.tsx"
    }
  ]
}