Combobox
A combobox is an input widget with an associated popup that enables users to select a value from a collection of possible values.
import {QCombobox} from "@qui/react"
Overview
The Combobox Pattern is versatile. We've based our implementation on this specification.
- When filterable is false, the combobox is select-only. This is functionally equivalent to an HTML select element.
- When filterable is true, the combobox accepts input text. When the user types, suggested values are filtered by their logical association to the input text.
Examples
Option Type
Options are configured using the options prop. Supply each option as a string or an object. If an option is provided as an object, you will need to supply the optionLabel to indicate which property will be used for the option's label. optionValue can be provided to indicate which property will be used to uniquely identify the option.
import {ReactNode} from "react"import {MapPin} from "lucide-react"import {QCombobox} from "@qui/react"export default function OptionAsString(): ReactNode {return (<div className="flex w-full flex-col items-center gap-4"><QComboboxclassName="max-w-[200px]"fullWidthoptions={["San Diego","Nashville","Denver","Miami","Las Vegas","New York City","San Francisco",]}placeholder="Select a City"startIcon={MapPin}/>{/* Option as object: must use optionLabel */}<QComboboxclassName="max-w-[200px]"fullWidthoptionLabel="name"options={[{id: 1, name: "San Diego"},{id: 2, name: "Nashville"},{id: 3, name: "Denver"},{disabled: true, id: 4, name: "Miami"},{id: 5, name: "Las Vegas"},{id: 6, name: "New York City"},{id: 7, name: "San Francisco"},]}placeholder="Select a City"startIcon={MapPin}/></div>)}
Select
When filterable is false, the combobox behaves similarly to the native <select>
element.
import {ReactNode} from "react"import {MapPin} from "lucide-react"import {QCombobox} from "@qui/react"export default function Showcase(): ReactNode {return (<QComboboxclassName="max-w-[200px]"fullWidthoptionLabel="name"options={[{id: 1, name: "San Diego"},{id: 2, name: "Nashville"},{id: 3, name: "Denver"},{disabled: true, id: 4, name: "Miami"},{id: 5, name: "Las Vegas"},{id: 6, name: "New York City"},{id: 7, name: "San Francisco"},]}placeholder="Select a City"startIcon={MapPin}/>)}
Multiple Selection
Pass the multiple property to enable multiple selection.
- Each selected value will render as dismissable QTag components.
- You can provide your own tags by supplying the renderTags prop.
- Use the limitTags property to limit the number of visible values when the component isn't focused.
Banana
Orange
Pineapple
import {ReactNode} from "react"import {Grape} from "lucide-react"import {QComboboxOption} from "@qui/base"import {QCombobox} from "@qui/react"interface Fruit extends QComboboxOption {id: numbername: string}const options: Fruit[] = [{id: 1, name: "Banana"},{id: 2, name: "Orange"},{id: 3, name: "Pineapple"},{id: 4, name: "Mango"},{id: 5, name: "Grapes"},{id: 6, name: "Watermelon"},{id: 7, name: "Strawberry"},{id: 8, name: "Blueberry"},]export default function Multiple(): ReactNode {return (<QComboboxclassName="w-[300px]"defaultValue={options.slice(0, 3)}filterablelabel="Choose your favorite fruits"multipleoptionLabel="name"optionValue="id"options={options}placeholder="Fruit"startIcon={Grape}/>)}
Filter
Pass the filterable property to enable the input field. The default filter function uses fuzzy matching to compare each option's label against the value of the input. Unmatched entries are hidden.
Customization
Use the label, hint, and error properties to describe the component. No These elements are automatically associated with the underlying <input>
element for optimal accessibility.
Error
San Diego
import {ReactNode} from "react"import {Info} from "lucide-react"import {QComboboxOption} from "@qui/base"import {QCombobox, QIcon} from "@qui/react"interface City extends QComboboxOption {id: numbername: string}const options: City[] = [{id: 1, name: "San Diego"},{id: 2, name: "Nashville"},{id: 3, name: "Denver"},{disabled: true, id: 4, name: "Miami"},{id: 5, name: "Las Vegas"},{id: 6, name: "New York City"},{id: 7, name: "San Francisco"},]export default function Customization(): ReactNode {return (<div className="grid justify-center"><div className="grid w-[300px] gap-y-5"><QComboboxfullWidthhint="Hint"label="Label"optionLabel="name"optionValue="id"options={options}placeholder="Select a City"/><QComboboxfullWidthhint={<span className="text-primary q-font-metadata-sm">Custom Hint</span>}label={<div className="mb-1 flex items-center gap-1 text-primary q-font-heading-xxs"><QIcon icon={Info} size="s" /><span>Custom Label</span></div>}optionLabel="name"options={options}placeholder="Select a City"/><QComboboxerror="Error"fullWidthlabel="Label"optionLabel="name"options={options}placeholder="Select a City"/><QComboboxdefaultValue={options[0]}fullWidthlabel="Read Only + Default Value"optionLabel="name"options={options}placeholder="Select a City"readOnly/><QComboboxdisabledfullWidthlabel="Disabled"optionLabel="name"optionValue="id"options={options}placeholder="Select a City"/><QComboboxfullWidthlabel="Loading Indicator"loadingoptionLabel="name"optionValue="id"options={options}placeholder="Select a City"/></div></div>)}
Custom Filter Function
To customize the filter function, supply the filterOptions property.
Custom Option Renderer
Since v1.3.0, you can supply your own option renderer using the renderOption prop.
- Your component must forward its ref to the root node.
- Your component must pass its props to the root node.
- Your component should destructure the
option
prop for custom rendering.
import {forwardRef, ReactNode} from "react"import {CheckIcon, MapPin} from "lucide-react"import {QCombobox, QComboboxOptionProps, QIcon} from "@qui/react"CustomOptions.displayName = "CustomOptions"interface Product {name: stringtype: string}const CustomOption = forwardRef<HTMLButtonElement,QComboboxOptionProps<Product>>(({"data-selected": selected, option, ...props}, ref) => {return (<button ref={ref} {...props}><div className="flex w-full justify-between"><div className="flex flex-col items-start"><div className="text-primary q-font-body-sm">{option.name}</div><div className="text-secondary q-font-metadata-md">{option.type}</div></div>{selected ? (<div className="flex items-center justify-end"><QIconclassName="q-foreground-1-secondary"icon={CheckIcon}size="m"/></div>) : null}</div></button>)})export default function CustomOptions(): ReactNode {return (<QComboboxclassName="max-w-[250px]"fullWidthoptionLabel="name"options={[{name: "QCC2076.WIN.1.0", type: "Software"},{name: "QUTS", type: "Tool"},] satisfies Product[]}placeholder="Select a Product"renderOption={CustomOption}startIcon={MapPin}/>)}
Select All
The following demo shows how to create a "Select All" dropdown option:
import {forwardRef, ReactNode, useMemo, useState} from "react"import {MapPin} from "lucide-react"import {clsx} from "@qui/base"import {QCheckbox, QCombobox, QComboboxOptionProps} from "@qui/react"SelectAll.displayName = "SelectAll"interface Product {name: string}export default function SelectAll(): ReactNode {const [value, setValue] = useState<Product[]>([])const [open, setOpen] = useState(false)const [allSelected, setAllSelected] = useState(false)const options = useMemo<Product[]>(() => [{name: "QCC2076.WIN.1.0"}, {name: "QUTS"}],[],)const deselectAll = () => {setAllSelected(false)setValue([])}const selectAll = () => {setAllSelected(true)setValue(options)}return (<QComboboxclassName="max-w-[250px]"fullWidthmultipleonChange={(event, value) => {setValue(value)setAllSelected(value.length === options.length)}}onOpenChange={setOpen}open={open}optionLabel="name"options={[{name: "Select All"}, ...options] satisfies Product[]}placeholder="Select a Product"renderOption={forwardRef<HTMLButtonElement,QComboboxOptionProps<Product>>((props, ref) => {if (props.option.name === "Select All") {return (<buttonref={ref}{...props}className={clsx(props.className, "border-b border-b-subtle")}onClick={() => {allSelected ? deselectAll() : selectAll()setOpen(false)}}><span className="flex gap-3"><QCheckbox checked={allSelected} />Select All</span></button>)}return <button {...props} ref={ref} />})}startIcon={MapPin}value={value}/>)}
Virtualization
Virtualization is implemented using the @tanstack/virtual library. For large datasets, use the virtual prop to render a virtual listbox. When enabled, this makes the container element the same height as the total number of items to be rendered, and then only renders the items that are currently visible.
The following example features a randomly-generated list of 10,000 cities.
import {ReactNode} from "react"import {faker} from "@faker-js/faker"import {SearchIcon} from "lucide-react"import {QCombobox} from "@qui/react"const data = faker.helpers.uniqueArray(faker.location.city, 10000).sort()export default function Virtual(): ReactNode {return (<QComboboxclassName="w-[250px]"filterablelabel="Cities"options={data}placeholder="Cities"startIcon={SearchIcon}virtual/>)}
Playground
TSX
<QComboboxdisableOptionToggle={false}filterable={false}fullWidthlabel="Label"limitTags={2}loading={false}multiple={false}optionLabel="name"placeholder="Placeholder..."showDropdownIcon={true}size={m}/>
Value
null
API
Props
Note that Option
refers to a generic type. It is inferred from the data supplied to the options prop. Examples:
// `Option` is a string<QCombobox options={["San Diego"]} />// `Option` is an object of type {name: string}<QCombobox optionLabel="name" options={[{name: "San Diego"}]} />
Name & Description | Option(s) | Default |
---|---|---|
Array of options. Note that Option refers to a generic type. |
| |
The component used for the root node. It can be a React component or
element. |
| 'div' |
HTML autocomplete attribute. |
| 'off' |
If true , the first option is automatically focused when the dropdown is
opened. Note that a selected option, if present, will be focused on open
instead of the first option. |
| true |
The className property of the Element
interface gets and sets the value of the
class attribute
of the specified element. |
| |
If true, the component will render a clear icon that resets the input field and
values on click. |
| true |
Default value of the input field. |
| '' |
The default value when uncontrolled. |
| |
The initial value. |
| |
If true, the dropdown will stay open after an option is selected. |
| false |
If true , the dropdown will stay open after an option is selected if the user
is holding the shift key. |
| true |
If true , the component will appear dimmed and will not be interactive. |
| false |
If true, prevents the active option from being deselected. Only applies when
multiple is false . |
| |
Box shadow severity of the panel, based on the five elevation styles
provided by QDS. A higher number means a more severe box shadow. Supply 0
to disable the box shadow. |
| 4 |
Optional error, triggers the invalid style variant if supplied. This element
is automatically associated with the component's input element for optimal
accessibility. | ReactNode | |
Error icon, displayed when . Supply as false to disable |
| |
If true, the component's input element will accept a value, enabling option
filtering. |
| false |
If provided, this function will be used to filter options instead of the
default function. |
| |
If true , the component will take up the full width of its parent
container. |
| false |
Used to determine the disabled state for a given option. |
| |
Optional hint describing the element. This element is automatically associated
with the component's input element for optimal accessibility. | ReactNode | |
Controlled id applied to the input element. If omitted, a unique
identifier will be automatically generated for error, label, and hint
accessibility. |
| |
attributes
applied to the input element. Use with caution. |
| {} |
Supply a ref to the input element. |
| |
The controlled value of the input field. |
| |
Optional label describing the element. Recommended. This element is
automatically associated with the component's input element for optimal
accessibility. | ReactNode | |
The maximum number of tags that will be visible when not focused. Set to -1
to disable the limit. Note that if renderTags is provided, this
prop will have no effect. |
| -1 |
Props applied to the listbox element that wraps the rendered options. |
| |
Ref applied to the listbox element that wraps the rendered options. Note
that this element is only rendered when the combobox is visible. If you are
trying to bind event listeners to the listbox, like for scroll events, you
should use listboxWrapperProps or listboxProps. |
| |
Props applied to the floating element that wraps the listbox element. |
| |
If true, a loading spinner will render in place of the dropdown icon. |
| false |
If true, multiple values can be selected at once. |
| false |
When no options are available, this is the message that shows. | ReactNode | 'No options...' |
Change function, fired when the selected option(s) change.
|
| |
Callback fired when the input value changes.
|
| |
Callback fired when the visibility of the dropdown panel changes.
|
| |
The controlled state for the component's visibility. |
| |
Used to determine the string label for a given option. Can also be supplied as
a function. This property is only used for options supplied as objects. |
| |
Used to determine the unique identifier for each option. Can also be supplied
as a function. If omitted, the optionLabel is used. This property is
only used for options supplied as objects. |
| |
HTML placeholder attribute. |
| |
If true, the component will not be interactive. |
| false |
Supply this property to render custom options. |
| |
Override the tag renderer which is responsible for rendering the active
values in the combobox when multiple is true .
|
| |
id applied to the root element. |
| |
If true , the dropdown icon will show. |
| true |
Size of the element, label, hint, and error messages. When these properties
are supplied as templates, size styles are omitted. |
| |
lucide-react icon, positioned before the input. If supplied as a
LucideIcon , the size will automatically match the size prop.
Supply as a ReactElement for additional customization. https://lucide.dev |
| |
The style global attribute
contains CSS styling
declarations to be applied to the element. | CSSProperties | |
| ||
Enables virtual rendering of the combobox options. visualization |
| |
Options passed to the useVirtualizer function. Refer to the
Tanstack Virtual docs
for detailed type information. Does nothing if virtual is false . |
| |
| 1000 |
Type
Array<Option>
Description
Array of options. Note that
Option
refers to a generic type.Related symbols
Type
| ElementType| ComponentType
Default
'div'
Description
The component used for the root node. It can be a React component or
element.
Type
boolean
Default
true
Description
If
true
, the first option is automatically focused when the dropdown is
opened. Note that a selected option, if present, will be focused on open
instead of the first option.Type
string
Description
The className property of the Element
interface gets and sets the value of the
class attribute
of the specified element.
Type
boolean
Default
true
Description
If true, the component will render a clear icon that resets the input field and
values on click.
Type
string
Default
''
Description
Default value of the input field.
Type
boolean
Description
The default value when uncontrolled.
Type
| Option| Array<Option>
Description
The initial value.
Type
boolean
Default
false
Description
If true, the dropdown will stay open after an option is selected.
Type
boolean
Default
true
Description
If
true
, the dropdown will stay open after an option is selected if the user
is holding the shift key.Type
boolean
Default
false
Description
If
true
, the component will appear dimmed and will not be interactive.Type
boolean
Description
If true, prevents the active option from being deselected. Only applies when
multiple is
false
.Type
| 0| 1| 2| 3| 4| 5| '0'| '1'| '2'| '3'| '4'| '5'
Default
4
Description
Box shadow severity of the panel, based on the five elevation styles
provided by QDS. A higher number means a more severe box shadow. Supply 0
to disable the box shadow.
Type
ReactNode
Description
Optional error, triggers the invalid style variant if supplied. This element
is automatically associated with the component's input element for optimal
accessibility.
Type
| false| LucideIconBase
Description
Error icon, displayed when . Supply as
false
to disableType
boolean
Default
false
Description
If true, the component's input element will accept a value, enabling option
filtering.
Type
(options: Array<Option>,inputValue: string,) => Array<Option>
Description
If provided, this function will be used to filter options instead of the
default function.
Type
boolean
Default
false
Description
If
true
, the component will take up the full width of its parent
container.Type
(option: Option,) => boolean
Description
Used to determine the disabled state for a given option.
Type
ReactNode
Description
Optional hint describing the element. This element is automatically associated
with the component's input element for optimal accessibility.
Type
string
Description
Controlled id applied to the input element. If omitted, a unique
identifier will be automatically generated for error, label, and hint
accessibility.
Type
HTMLAttributes<HTMLInputElement>
Default
{}
Description
attributes
applied to the
input
element. Use with caution.Type
Ref<HTMLInputElement>
Description
Supply a ref to the input element.
Type
string
Description
The controlled value of the input field.
Type
ReactNode
Description
Optional label describing the element. Recommended. This element is
automatically associated with the component's input element for optimal
accessibility.
Type
number
Default
-1
Description
The maximum number of tags that will be visible when not focused. Set to -1
to disable the limit. Note that if renderTags is provided, this
prop will have no effect.
Type
HTMLAttributes<HTMLDivElement>
Description
Props applied to the listbox element that wraps the rendered options.
Type
Ref<HTMLDivElement>
Description
Ref applied to the listbox element that wraps the rendered options. Note
that this element is only rendered when the combobox is visible. If you are
trying to bind event listeners to the listbox, like for scroll events, you
should use listboxWrapperProps or listboxProps.
Type
HTMLAttributes<HTMLDivElement>
Description
Props applied to the floating element that wraps the listbox element.
Type
boolean
Default
false
Description
If true, a loading spinner will render in place of the dropdown icon.
Type
boolean
Default
false
Description
If true, multiple values can be selected at once.
Type
ReactNode
Default
'No options...'
Description
When no options are available, this is the message that shows.
Type
(event:| KeyboardEvent| MouseEvent| SyntheticEvent| object,value: Multiple extends false? Option | object: Array<Option>,reason:| 'clear'| 'selectOption'| 'removeOption'| 'input'| 'reset',details?: {option: Option},) => void
Description
Change function, fired when the selected option(s) change.
- eventthe DOM event associated with the change.
- valuethe updated value.
- reasonthe cause of the event.
- detailsevent details.
Type
(value: string,event: ChangeEvent | object,reason:| 'input'| 'reset'| 'clear',) => void
Description
Callback fired when the input value changes.
- valuethe updated value of the input field.
- eventthe DOM event associated with the change. May be null.
- reasonthe cause of the event.
Type
(open: boolean,event: Event,reason?:| 'ancestor-scroll'| 'arrow-left'| 'arrow-right'| 'blur'| 'clear'| 'click'| 'escape-key'| 'focus'| 'hover'| 'input'| 'list-navigation'| 'outside-press'| 'reference-press'| 'remove-option'| 'safe-polygon'| 'select-option',) => void
Description
Callback fired when the visibility of the dropdown panel changes.
- openthe updated state.
- eventthe DOM event associated with the change.
- reasonthe cause of the event.
Type
boolean
Description
The controlled state for the component's visibility.
Type
| string| number| symbol| ((option: Option,) => string)
Description
Used to determine the string label for a given option. Can also be supplied as
a function. This property is only used for options supplied as objects.
Related symbols
Type
| string| number| symbol| ((option: Option,) => string)
Description
Used to determine the unique identifier for each option. Can also be supplied
as a function. If omitted, the optionLabel is used. This property is
only used for options supplied as objects.
Related symbols
Type
string
Description
HTML placeholder attribute.
Type
boolean
Default
false
Description
If true, the component will not be interactive.
Type
(props: QComboboxOptionProps,) => ReactNode
Description
Supply this property to render custom options.
Related symbols
Type
(value: Array<Option>,getTagProps: (index: number,) => {'data-tag-index': numberdisabled: booleandismissable: booleangetOptionLabel: (option: Option,) => stringonDelete: (event: SyntheticEvent,option: Option,) => voidreadOnly: booleantabIndex: -1},) => ReactNode
Description
Override the tag renderer which is responsible for rendering the active
values in the combobox when multiple is
true
.- valuethe option value.
- getTagPropsprop spreader function, returns props for the tag element.
Type
string
Description
id applied to the root element.
Type
boolean
Default
true
Description
If
true
, the dropdown icon will show.Type
| 's'| 'm'| 'l'
Description
Size of the element, label, hint, and error messages. When these properties
are supplied as templates, size styles are omitted.
Type
| LucideIcon| ReactNode
Description
lucide-react icon, positioned before the input. If supplied as a
LucideIcon
, the size will automatically match the size prop.
Supply as a ReactElement
for additional customization. https://lucide.devType
CSSProperties
Description
The style global attribute
contains CSS styling
declarations to be applied to the element.
Type
| Option| Array<Option>| object
Description
Controlled value for this component. This prop is used to control the
selected option (or options if multiple is
true
).Type
boolean
Description
Enables virtual rendering of the combobox options. visualization
Type
Partial<VirtualizerOptions<HTMLElement,HTMLElement>>
Description
Options passed to the useVirtualizer function. Refer to the
Tanstack Virtual docs
for detailed type information. Does nothing if virtual is
false
.Keyboard Events
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
QComboboxOptionProps
Name & Description | Option(s) | Default |
---|---|---|
The option. |
| |
If true , the option is currently highlighted in the listbox. This indicates
that the combobox option is focused. Note that all "focus" in this context is
virtual, and does not indicate DOM focus. |
| |
The option's numeric position in the dropdown. |
| |
If true , the option is currently selected. |
| |
If true , virtual rendering is enabled. |
|
Type
Option
Description
The option.
Type
boolean
Description
If
true
, the option is currently highlighted in the listbox. This indicates
that the combobox option is focused. Note that all "focus" in this context is
virtual, and does not indicate DOM focus.Type
number
Description
The option's numeric position in the dropdown.
Type
boolean
Description
If
true
, the option is currently selected.Type
boolean
Description
If
true
, virtual rendering is enabled.