HapplyUI

Combo Box

A searchable multi-select combo box with compound components. Use ComboBox.Composed for the simple flat-props API, or compose with Root, SearchTrigger, Content, Item, and Tags for full control over item rendering and tag display.


Installation

bunx @happlyui/cli@latest add combo-box

Dependencies

npm packages

  • @remixicon/react
  • @radix-ui/react-scroll-area
  • react-remove-scroll

Registry dependencies

These are automatically installed when you add this component.

  • form-field-context
  • use-form-field-binding
  • popover
  • input
  • tag
  • happly-ui-utils

Usage

import * as ComboBox from "@/components/ui/combo-box"

// Simple usage
<ComboBox.Composed
  options={options}
  value={selected}
  onValueChange={setSelected}
/>

// Compound usage
<ComboBox.Root options={options} value={selected} onValueChange={setSelected}>
  <ComboBox.SearchTrigger />
  <ComboBox.Content />
  <ComboBox.Tags />
</ComboBox.Root>

Examples

Default

Basic multi-select combo box with label.

<ComboBox.Composed
  options={options}
  value={value}
  onValueChange={setValue}
/>

With Pre-selected Values

Combo box with initial selections, useful for editing saved forms.

AI
Product
SaaS
<ComboBox.Composed
  options={options}
  value={['ai', 'product', 'saas']}
  onValueChange={setValue}
/>

Uncontrolled

Use defaultValue for uncontrolled mode in forms.

Grants
Loans
<ComboBox.Composed
  options={options}
  defaultValue={['grants', 'loans']}
  name="sectors"
/>

Form Submission

Use the name prop to include selected values in form submissions via hidden inputs.

AI
SaaS
<ComboBox.Composed
  options={options}
  value={value}
  onValueChange={setValue}
  name="tags"
/>

Sizes

All three input sizes: medium (default), small, and xsmall.

AI
AI
Product
AI
<ComboBox.Composed options={options} value={value} onValueChange={setValue} />
<ComboBox.Composed options={options} size="small" />
<ComboBox.Composed options={options} size="xsmall" />

Selection Constraints

Limit selections with max, min, or both combined.

AI
Grants
VC Funding
Grants
VC Funding
<ComboBox.Composed options={options} value={value} onValueChange={setValue} max={3} />

Tag Variants

Gray (default), stroke tag style, and selectAllLabel summary tag.

AI
SaaS
AI
SaaS
All tags
<ComboBox.Composed options={options} tagVariant="stroke" />

States

Error and disabled states.

Grants
VC Funding
<ComboBox.Composed options={options} hasError />
<ComboBox.Composed options={options} disabled />

Customization

Custom icon, placeholder text, and empty message.

<ComboBox.Composed options={options} icon={RiMapPinLine} placeholder="Search cities..." />

With Icons

Options with leading icons — supports React components and image URLs.

Utility Payment
United States
Germany
<ComboBox.Composed options={iconOptions} value={value} onValueChange={setValue} />

Compound Custom Items

Use the compound API for fully custom item rendering with checkbox indicators, avatars, and custom layouts.

Alice Johnson
<ComboBox.Root options={users} value={selected} onValueChange={setSelected}>
  <ComboBox.SearchTrigger placeholder="Search team members..." />
  <ComboBox.Content>
    {filteredOptions.map(user => (
      <ComboBox.Item key={user.value} value={user.value}>
        <Checkbox checked={isSelected(user.value)} />
        <Avatar src={user.avatar} />
        <span>{user.name}</span>
        <ComboBox.ItemIndicator selected={isSelected(user.value)} />
      </ComboBox.Item>
    ))}
  </ComboBox.Content>
  <ComboBox.Tags variant="stroke" />
</ComboBox.Root>

Compound Custom Tags

Omit ComboBox.Tags and render your own tag display using useComboBoxContext().

Alice
Bob
<ComboBox.Root options={users} value={selected} onValueChange={setSelected}>
  <ComboBox.SearchTrigger />
  <ComboBox.Content />
  <CustomTags />
</ComboBox.Root>

Preview

Preview mode renders the option list inline in the DOM and hides tags.

Grants
Incubators & Accelerators
VC Funding
Competition
Loans
Hiring
Training
<ComboBox.Composed
  options={options}
  value={value}
  onValueChange={setValue}
  preview
/>

Custom Max Height

Override the dropdown height via the --combobox-content-max-height CSS variable on Content.

<ComboBox.Root options={options} value={value} onValueChange={setValue}>
  <ComboBox.SearchTrigger />
  <ComboBox.Content className="[--combobox-content-max-height:350px]" />
  <ComboBox.Tags />
</ComboBox.Root>

API Reference

ComboBox.Root

Context provider and state orchestrator. Wraps all compound sub-components.

PropTypeDefaultDescription
optionsComboBoxOption[]-Available options ({ value, label, icon? }).
valuestring[]-Currently selected values (controlled).
defaultValuestring[][]Default selected values (uncontrolled).
onValueChange(values: string[], selectedOptions: ComboBoxOption[]) => void-Callback when selection changes.
namestring-Form field name — renders hidden inputs for form submission.
maxnumberInfinityMaximum number of selections.
minnumber0Minimum selections (prevents removing below this).
disabledbooleanfalseDisabled state.
hasErrorbooleanfalseError state.
size'medium' | 'small' | 'xsmall''medium'Input size.
previewbooleanfalsePreview mode — renders the option list inline in the DOM and hides tags.
onOpenChange(open: boolean) => void-Callback when dropdown open state changes.

ComboBox.SearchTrigger

Search input trigger with leading icon. Uses inputVariants for styling.

PropTypeDefaultDescription
leadingIconReact.ElementTypeRiSearchLineLeading icon component.
trailingIconReact.ElementTypeRiArrowDownSLineTrailing icon component.
placeholderstring'Choose or search...'Search input placeholder.

ComboBox.Content

Dropdown popover content with scroll area. When children are omitted, auto-renders items from filtered options.

PropTypeDefaultDescription
emptyMessagestring'No results found.'Message when no options match the search.
childrenReact.ReactNode-Custom content — overrides default item rendering.

ComboBox.Item

A single option row. When children are provided, renders custom content; otherwise renders icon + label from options.

PropTypeDefaultDescription
valuestring-The option value this item represents.
childrenReact.ReactNode-Custom content for the item.

ComboBox.ItemIcon

Polymorphic icon for items. Supports React components and image URL strings.

PropTypeDefaultDescription
asReact.ElementType | string-Icon component or image URL.

ComboBox.ItemIndicator

Check indicator for selected items. Defaults to RiCheckLine.

PropTypeDefaultDescription
selectedboolean-Whether the item is selected.
childrenReact.ReactNode-Custom indicator content.

ComboBox.Empty

Empty state content shown when no options match.

PropTypeDefaultDescription
childrenReact.ReactNode'No results found.'Custom empty message.

ComboBox.Tags

Tag display area for selected items. Omit entirely for custom tag rendering.

PropTypeDefaultDescription
variant'stroke' | 'gray''gray'Visual variant for tags.
selectAllLabelstring-When provided and all options selected, show a single summary tag.

ComboBox.Composed

Convenience flat-props wrapper. Assembles Root + SearchTrigger + Content + Tags internally. Drop-in replacement for the v2 API.

PropTypeDefaultDescription
iconReact.ElementTypeRiSearchLineLeading icon component.
placeholderstring'Choose or search...'Search input placeholder.
emptyMessagestring'No results found.'Message when no options match.
selectAllLabelstring-Summary tag label when all selected.
tagVariant'stroke' | 'gray''gray'Visual variant for tags.

useComboBoxContext

Hook to access ComboBox state from custom child components. Returns options, value, filteredOptions, isSelected, toggle, remove, removeAll, search, setSearch, open, disabled, and more.

PropTypeDefaultDescription

Previous
Textarea