Combobox
An editable field that filters and selects from a list of options.
Installation
Import from the Reflow workspace package.
Playground
Open demoimport { Combobox } from '@rtzll/reflow'
import { type Handle } from 'remix/component'
export function Example(handle: Handle) {
const components = [
{
"label": "Accordion",
"value": "accordion"
},
{
"label": "Badge",
"value": "badge"
},
{
"label": "Button",
"value": "button"
},
{
"label": "Card",
"value": "card"
},
{
"label": "CheckboxGroup",
"value": "checkboxgroup"
},
{
"label": "ColorPicker",
"value": "colorpicker"
},
{
"label": "Combobox",
"value": "combobox"
},
{
"label": "Dialog",
"value": "dialog"
},
{
"label": "Dropdown",
"value": "dropdown"
},
{
"label": "InputGroup",
"value": "inputgroup"
},
{
"label": "RadioGroup",
"value": "radiogroup"
},
{
"label": "Select",
"value": "select"
},
{
"label": "Sidebar",
"value": "sidebar"
},
{
"label": "Slider",
"value": "slider"
},
{
"label": "Switch",
"value": "switch"
},
{
"label": "Table",
"value": "table"
},
{
"label": "Tabs",
"value": "tabs"
}
]
const options = ['Apple', 'Banana', 'Cherry', 'Mango'].map((label) => ({ value: label.toLowerCase(), label }))
return () => (
<>
<Combobox variant="bordered" multiple={true} creatable={false} hideSelected={false} error={false} disabled={false} size="default" label="Components" placeholder="Add components…" emptyMessage="No component found." options={components} defaultValues={['button', 'combobox']} />
</>
)
}Basic
import { Combobox } from '@rtzll/reflow'
import { type Handle } from 'remix/component'
export function Example(handle: Handle) {
const options = ['Apple', 'Banana', 'Cherry', 'Mango'].map((label) => ({ value: label.toLowerCase(), label }))
return () => (
<>
<Combobox label="Framework" options={frameworks} placeholder="Select a framework…" />
</>
)
}With icons
import { Combobox, Icon } from '@rtzll/reflow'
import { type Handle } from 'remix/component'
export function Example(handle: Handle) {
const options = ['Apple', 'Banana', 'Cherry', 'Mango'].map((label) => ({ value: label.toLowerCase(), label }))
return () => (
<>
<Combobox label="View" leadingIcon={<Icon name="search" />} options={views} placeholder="Jump to view…" />
</>
)
}Multiple selection
import { Combobox } from '@rtzll/reflow'
import { type Handle } from 'remix/component'
export function Example(handle: Handle) {
const options = ['Apple', 'Banana', 'Cherry', 'Mango'].map((label) => ({ value: label.toLowerCase(), label }))
return () => (
<>
<Combobox label="Frameworks" options={frameworks} multiple defaultValues={['next', 'astro']} />
</>
)
}Create from the query
import { Combobox } from '@rtzll/reflow'
import { type Handle } from 'remix/component'
export function Example(handle: Handle) {
const options = ['Apple', 'Banana', 'Cherry', 'Mango'].map((label) => ({ value: label.toLowerCase(), label }))
return () => (
<>
<Combobox label="Components" options={components} multiple creatable onCreate={saveComponent} />
</>
)
}Hide picked rows
import { Combobox } from '@rtzll/reflow'
import { type Handle } from 'remix/component'
export function Example(handle: Handle) {
const options = ['Apple', 'Banana', 'Cherry', 'Mango'].map((label) => ({ value: label.toLowerCase(), label }))
return () => (
<>
<Combobox label="Components" options={components} multiple hideSelected defaultValues={['button', 'combobox']} />
</>
)
}Variants
import { Combobox } from '@rtzll/reflow'
import { type Handle } from 'remix/component'
export function Example(handle: Handle) {
const options = ['Apple', 'Banana', 'Cherry', 'Mango'].map((label) => ({ value: label.toLowerCase(), label }))
return () => (
<>
<Combobox label="Bordered" options={frameworks} variant="bordered" />
<Combobox label="Ghost" options={frameworks} variant="ghost" />
</>
)
}Long list
Filter the list, then use the arrow keys and Enter to choose an option.
import { Combobox } from '@rtzll/reflow'
import { type Handle } from 'remix/component'
export function Example(handle: Handle) {
const options = ['Apple', 'Banana', 'Cherry', 'Mango'].map((label) => ({ value: label.toLowerCase(), label }))
const timezones = Intl.supportedValuesOf('timeZone').map((label) => ({ value: label, label }))
return () => (
<>
<Combobox label="Timezone" options={timezones} />
</>
)
}Error & disabled
import { Combobox } from '@rtzll/reflow'
import { type Handle } from 'remix/component'
export function Example(handle: Handle) {
const options = ['Apple', 'Banana', 'Cherry', 'Mango'].map((label) => ({ value: label.toLowerCase(), label }))
return () => (
<>
<Combobox label="Framework" options={frameworks} error />
<Combobox label="Framework" options={frameworks} placeholder="Disabled" disabled />
</>
)
}API Reference
Public props for the Reflow implementation. Native controls also accept their standard HTML attributes and Remix event mixes.
Combobox
| Prop | Type | Default | Description |
|---|---|---|---|
multiple | boolean | — | Enables multiple selected values. |
values | readonly string[] | — | Controlled selected values. |
defaultValues | readonly string[] | — | Initial selected values. |
onValuesChange | ((values: string[]) => void) | — | Called when the selected values change. |
creatable | boolean | — | Allows a new option to be created from the query. |
onCreate | ((value: string) => void) | — | Receives the newly created option. |
emptyMessage | string | — | Message shown when no options match. |
hideSelected | boolean | — | Hides picked options from the list. |
error | boolean | — | Validation message or error state. |
label* | string | — | Accessible name or visible label for the control. |
options* | readonly ChoiceOption[] | — | Choices available to the user. |
name | string | — | Name used when the control participates in a form. |
defaultValue | string | — | Initial value for an uncontrolled component. |
value | string | null | — | Current value when controlled by the parent. |
onValueChange | ((value: string | null) => void) | — | Called when the selected value changes. |
disabled | boolean | — | Prevents interaction and conveys the disabled state. |
placeholder | string | Choose an option… | Hint shown while the value is empty. |
variant | "ghost" | "bordered" | bordered | Visual or layout treatment. |
size | "default" | "compact" | — | Control density or icon-button dimensions. |
ChoiceOption
| Prop | Type | Default | Description |
|---|---|---|---|
value* | string | — | Value submitted when this option is selected. |
label* | string | — | Text shown for the option. |
icon | RemixNode | — | Icon content. |
disabled | boolean | — | Prevents interaction and conveys the disabled state. |
searchValue | string | string[] | — | Additional text matched by filtering or typeahead. |