Skip to main content
Version: Next

Combobox

Use Combobox to provide a searchable alternative to traditional select dropdowns. Supports filtering, custom values, debounced inputs, and comprehensive state feedback.

import { Combobox } from '@editora/ui-react';

function Example() {
const [value, setValue] = React.useState('');

return (
<Combobox
value={value}
onChange={setValue}
placeholder="Choose an option..."
clearable
>
<Combobox.Option value="opt-1">Option 1</Combobox.Option>
<Combobox.Option value="opt-2">Option 2</Combobox.Option>
<Combobox.Option value="opt-3">Option 3</Combobox.Option>
</Combobox>
);
}

Props

Combobox (Root)

PropTypeDefaultDescription
valuestring-Currently selected value.
openboolean-Whether the dropdown is open.
state'idle' | 'loading' | 'error' | 'success''idle'Workflow state for async operations.
stateTextstring-Descriptive text for the current state.
placeholderstring-Placeholder text for the input.
labelstring-Accessible label for the combobox.
descriptionstring-Helper text below the label.
emptyTextstring-Text shown when no options match the filter.
size'sm' | 'md' | 'lg' | '1' | '2' | '3''md'Input size.
variant'classic' | 'surface' | 'soft''surface'Visual style variant.
radius'none' | 'large' | 'full' | string-Corner radius style.
clearablebooleanfalseShow clear button when value is set.
disabledbooleanfalseDisable the combobox.
readOnlybooleanfalsePrevent user interaction.
requiredbooleanfalseMark as required.
autofocusbooleanfalseAuto-focus on mount.
debouncenumber-Debounce delay (ms) for onDebouncedInput.
validation'error' | 'success' | 'none''none'Validation state styling.
noFilterbooleanfalseDisable client-side filtering.
allowCustombooleanfalseAllow entering custom values not in options.
onChange(value: string) => void-Fired when value changes.
onInput(query: string) => void-Fired on input changes.
onDebouncedInput(query: string) => void-Fired after debounce delay.
onSelect(value: string, label: string) => void-Fired when option is selected.
onOpen() => void-Fired when dropdown opens.
onClose() => void-Fired when dropdown closes.
onOpenDetail(detail) => void-Fired with open details.
onCloseDetail(detail) => void-Fired with close details.
onClear() => void-Fired when cleared.

Sub-components

Combobox.Option

Represents a selectable option in the combobox.

PropTypeDefaultDescription
valuestringRequiredThe option's value.
descriptionstring-Optional description text shown below the label.
childrenReactNode-The display label for the option.
disabledboolean-Disable this option.

Examples

Basic Combobox

<Combobox placeholder="Select an item...">
<Combobox.Option value="apple">Apple</Combobox.Option>
<Combobox.Option value="banana">Banana</Combobox.Option>
<Combobox.Option value="cherry">Cherry</Combobox.Option>
</Combobox>

With Descriptions

<Combobox label="Select Team Member" placeholder="Search...">
<Combobox.Option value="alice" description="Frontend Engineer">
Alice Johnson
</Combobox.Option>
<Combobox.Option value="bob" description="Backend Engineer">
Bob Smith
</Combobox.Option>
<Combobox.Option value="carol" description="Product Manager">
Carol Williams
</Combobox.Option>
</Combobox>

Controlled State

function ControlledCombobox() {
const [value, setValue] = React.useState('');
const [query, setQuery] = React.useState('');
const [state, setState] = React.useState<'idle' | 'loading' | 'error' | 'success'>('idle');

return (
<Combobox
value={value}
state={state}
stateText={
state === 'loading'
? 'Searching...'
: state === 'error'
? 'Search failed'
: state === 'success'
? 'Results loaded'
: ''
}
onInput={(nextQuery) => {
setQuery(nextQuery);
setState('loading');
// Simulate async search
setTimeout(() => {
setState(nextQuery.length > 2 ? 'success' : 'idle');
}, 500);
}}
onChange={setValue}
validation={state === 'error' ? 'error' : state === 'success' ? 'success' : 'none'}
>
<Combobox.Option value="opt1">Option 1</Combobox.Option>
<Combobox.Option value="opt2">Option 2</Combobox.Option>
<Combobox.Option value="opt3">Option 3</Combobox.Option>
</Combobox>
);
}

With Custom Values

<Combobox
allowCustom
label="Add New Tag"
placeholder="Type to create custom tag..."
description="Press Enter to add a custom value"
>
<Combobox.Option value="urgent">Urgent</Combobox.Option>
<Combobox.Option value="standard">Standard</Combobox.Option>
<Combobox.Option value="low">Low Priority</Combobox.Option>
</Combobox>

With Debounced Input

<Combobox
debounce={300}
label="Search Organizations"
placeholder="Type organization name..."
onDebouncedInput={(query) => {
// Perform async search after debounce
console.log('Searching for:', query);
}}
>
<Combobox.Option value="acme">ACME Corp</Combobox.Option>
<Combobox.Option value="globex">Globex Corporation</Combobox.Option>
</Combobox>

Validation States

{/* Success */}
<Combobox validation="success">...</Combobox>

{/* Error */}
<Combobox validation="error">...</Combobox>

{/* With State */}
<Combobox state="error" validation="error">...</Combobox>
<Combobox state="success" validation="success">...</Combobox>

Sizing

<Combobox size="sm">...</Combobox>
<Combobox size="md">...</Combobox>
<Combobox size="lg">...</Combobox>

Variants

<Combobox variant="classic">...</Combobox>
<Combobox variant="surface">...</Combobox>
<Combobox variant="soft">...</Combobox>