Combobox
An input combined with a list of predefined items to select.
Installation
pnpm dlx shadcn@latest add @lumi-ui/combobox
Anatomy
<Combobox>
<ComboboxTrigger />
<ComboboxInputGroup /> // or <ComboboxInput />
<ComboboxChips>
<ComboboxChip />
</ComboboxChips>
<ComboboxContent>
<ComboboxStatus />
<ComboboxEmpty />
<ComboboxList>
<ComboboxRow>
<ComboboxItemContent />
</ComboboxRow>
<ComboboxSeparator />
<ComboboxGroup>
<ComboboxGroupLabel />
</ComboboxGroup>
<ComboboxCollection />
</ComboboxList>
</ComboboxContent>
</Combobox>Features
With Clear and Trigger Button
Input Inside Popup
Use ComboboxTrigger instead of ComboboxInputGroup to place the input inside the popup. Style ComboboxInput to remove the border.
Grouped
Cookbook
Using Scroll Area
Multiple Selection
Creatable
Async Items (Single)
Async Items (Multiple)
Customization
Lumi UI exports all primitive components with minimal styles from Base UI to ensure maximum flexibility. Below is an example of how to compose Linear-style combobox by mixing Composite components with raw primitives.
API Reference
ComboboxInputGroup
A high-level input component that combines the Input, Clear, and Trigger into a single styled element.
ComboboxContent
A high-level container component that combines the Portal, Positioner, and Popup into a single styled element for the dropdown content.
ComboboxItemContent
A high-level item component that combines the Item and ItemIndicator into a single styled element with configurable icon positioning.
The "Hit-Test" Philosophy
You might notice we use a pseudo-element (before:) to render the hover state, rather than styling the container directly. While simple margins can also create a "pill" shape, that approach creates a UX flaw: it shrinks the clickable area.
By separating the visual layer (the pill) from the interactive layer (the full-width row), we achieve the best of both worlds:
- Forgiving Interactivity: Users can hover or click anywhere across the full width of the menu item—even the empty whitespace—to trigger the selection.
- Refined Aesthetics: The highlight remains visually tucked in and detached, mimicking the polished feel of native operating system menus (a pattern we adopted from the excellent Base UI).
Feeling too complex? You can always replace pseudo-element with data-[highlighted]:bg-accent and data-[highlighted]:text-accent-foreground.
Because the background color lives on a pseudo-element, applying rounded-* classes directly to the component won't change the highlight's corners. To customize the radius, target the pseudo-element directly: data-[highlighted]:before:rounded-lg.
💡Mind the gap: If you increase the highlight inset (inset-x-4), ensure you increase the item padding (pl-6) so text doesn't overflow the visual selection.