Components

Combobox

Searchable select with popover overlay, built on Base UI Popover and cmdk.

Category: Form / Base UI Overlay

Dependencies: @base-ui-components/react, cmdk

Import

import {
  Combobox,
  ComboboxTrigger,
  ComboboxContent,
  ComboboxInput,
  ComboboxList,
  ComboboxItem,
  ComboboxEmpty,
  ComboboxGroup,
} from "@hareru/ui"

Exports

NameTypeDescription
ComboboxComponentRoot component managing open state and context
ComboboxTriggerComponentButton that toggles the popover
ComboboxContentComponentPopover panel with the search command palette
ComboboxInputComponentSearch input with built-in search icon
ComboboxListComponentScrollable list of items
ComboboxItemComponentIndividual selectable option
ComboboxEmptyComponentShown when no items match the search
ComboboxGroupComponentGroups related items with a heading

Types

export interface ComboboxProps {
  open?: boolean
  onOpenChange?: (open: boolean) => void
  defaultOpen?: boolean
  children: React.ReactNode
  modal?: boolean
}

Key Props

PropTypeDefaultDescription
openbooleanControlled open state
onOpenChange(open: boolean) => voidCallback when open state changes
defaultOpenbooleanfalseInitial open state (uncontrolled)
modalbooleanRender as modal, blocking page interaction

Structure

  • ComboboxTrigger [trigger] (expected)
  • ComboboxContent [content] (expected)
    • ComboboxInput [input] (expected)
    • ComboboxList [container] (expected)
      • ComboboxItem [item] (expected) ×N
      • ComboboxGroup [container] ×N
    • ComboboxEmpty [content]

(expected) = recommended in canonical composition, not runtime-required.

States

StateTypeValuesDefaultCSS Reflection
openboolean

Accessibility

  • Roles: combobox
  • Keyboard:
    • Arrow keys to navigate options
    • Enter to select
    • Escape to close
  • Notes: ARIA combobox pattern with integrated search and listbox.

Usage

import { useState } from "react"
import {
  Combobox,
  ComboboxTrigger,
  ComboboxContent,
  ComboboxInput,
  ComboboxList,
  ComboboxItem,
  ComboboxEmpty,
} from "@hareru/ui"

const fruits = [
  { value: "apple", label: "Apple" },
  { value: "banana", label: "Banana" },
  { value: "cherry", label: "Cherry" },
]

function FruitCombobox() {
  const [value, setValue] = useState("")

  return (
    <Combobox>
      <ComboboxTrigger>{value || "Select a fruit..."}</ComboboxTrigger>
      <ComboboxContent>
        <ComboboxInput placeholder="Search..." />
        <ComboboxList>
          <ComboboxEmpty>No results found</ComboboxEmpty>
          {fruits.map((fruit) => (
            <ComboboxItem
              key={fruit.value}
              value={fruit.value}
              onSelect={() => setValue(fruit.label)}
            >
              {fruit.label}
            </ComboboxItem>
          ))}
        </ComboboxList>
      </ComboboxContent>
    </Combobox>
  )
}

// With groups
<Combobox>
  <ComboboxTrigger>Select...</ComboboxTrigger>
  <ComboboxContent>
    <ComboboxInput placeholder="Search..." />
    <ComboboxList>
      <ComboboxEmpty>No results found</ComboboxEmpty>
      <ComboboxGroup heading="Fruits">
        <ComboboxItem value="apple" onSelect={() => setValue("Apple")}>Apple</ComboboxItem>
        <ComboboxItem value="banana" onSelect={() => setValue("Banana")}>Banana</ComboboxItem>
      </ComboboxGroup>
    </ComboboxList>
  </ComboboxContent>
</Combobox>

Notes

  • ComboboxItem automatically closes the popover when selected via internal context.
  • ComboboxContent is positioned below the trigger with 4px offset, aligned to the start.
  • The ComboboxInput includes a built-in search icon — no need to add one manually.
  • Filtering is handled by cmdk internally based on item text content.

On this page