Combobox
A single input field that combines the functionality of a select and input.
Anatomy
To set up the combobox correctly, you'll need to understand its anatomy and how we name its parts.
Each part includes a
data-part
attribute to help identify them in the DOM.
Examples
Learn how to use the Combobox
component in your project. Let's take a look at the most basic
example
import { Combobox, Portal } from '@ark-ui/react'
export const Basic = () => {
const items = ['React', 'Solid', 'Vue']
return (
<Combobox.Root items={items} lazyMount unmountOnExit>
<Combobox.Label>Framework</Combobox.Label>
<Combobox.Control>
<Combobox.Input />
<Combobox.Trigger>Open</Combobox.Trigger>
<Combobox.ClearTrigger>Clear</Combobox.ClearTrigger>
</Combobox.Control>
<Portal>
<Combobox.Positioner>
<Combobox.Content>
<Combobox.ItemGroup>
<Combobox.ItemGroupLabel>Frameworks</Combobox.ItemGroupLabel>
{items.map((item) => (
<Combobox.Item key={item} item={item}>
<Combobox.ItemText>{item}</Combobox.ItemText>
<Combobox.ItemIndicator>✓</Combobox.ItemIndicator>
</Combobox.Item>
))}
</Combobox.ItemGroup>
</Combobox.Content>
</Combobox.Positioner>
</Portal>
</Combobox.Root>
)
}
import { For } from 'solid-js'
import { Portal } from 'solid-js/web'
import { Combobox } from '@ark-ui/solid'
export const Basic = () => {
const items = ['React', 'Solid', 'Vue']
return (
<Combobox.Root items={items} multiple>
<Combobox.Label>Framework</Combobox.Label>
<Combobox.Control>
<Combobox.Input />
<Combobox.Trigger>Open</Combobox.Trigger>
<Combobox.ClearTrigger>Clear</Combobox.ClearTrigger>
</Combobox.Control>
<Portal>
<Combobox.Positioner>
<Combobox.Content>
<Combobox.ItemGroup>
<Combobox.ItemGroupLabel>Frameworks</Combobox.ItemGroupLabel>
<For each={items}>
{(item) => (
<Combobox.Item item={item}>
<Combobox.ItemText>{item}</Combobox.ItemText>
<Combobox.ItemIndicator>✓</Combobox.ItemIndicator>
</Combobox.Item>
)}
</For>
</Combobox.ItemGroup>
</Combobox.Content>
</Combobox.Positioner>
</Portal>
</Combobox.Root>
)
}
<script setup lang="ts">
import { ref } from 'vue'
import { Combobox } from '@ark-ui/vue'
const items = ref(['React', 'Solid', 'Vue'])
</script>
<template>
<Combobox.Root :items="items">
<Combobox.Label>Framework</Combobox.Label>
<Combobox.Control>
<Combobox.Input />
<Combobox.Trigger>Open</Combobox.Trigger>
<Combobox.ClearTrigger>Clear</Combobox.ClearTrigger>
</Combobox.Control>
<Teleport to="body">
<Combobox.Positioner>
<Combobox.Content>
<Combobox.ItemGroup>
<Combobox.ItemGroupLabel>Frameworks</Combobox.ItemGroupLabel>
<Combobox.Item v-for="item in items" :key="item" :item="item">
<Combobox.ItemText>{{ item }}</Combobox.ItemText>
<Combobox.ItemIndicator>✓</Combobox.ItemIndicator>
</Combobox.Item>
</Combobox.ItemGroup>
</Combobox.Content>
</Combobox.Positioner>
</Teleport>
</Combobox.Root>
</template>
Advanced Customization
Extended example that shows usage with complex item objects, including disabled state for certain options.
import { Combobox, Portal } from '@ark-ui/react'
export const Advanced = () => {
const items = [
{ label: 'React', value: 'react' },
{ label: 'Solid', value: 'solid' },
{ label: 'Vue', value: 'vue' },
{ label: 'Svelte', value: 'svelte', disabled: true },
]
return (
<Combobox.Root items={items} multiple>
<Combobox.Label>Framework</Combobox.Label>
<Combobox.Control>
<Combobox.Input />
<Combobox.Trigger>Open</Combobox.Trigger>
<Combobox.ClearTrigger>Clear</Combobox.ClearTrigger>
</Combobox.Control>
<Portal>
<Combobox.Positioner>
<Combobox.Content>
<Combobox.ItemGroup>
<Combobox.ItemGroupLabel>Frameworks</Combobox.ItemGroupLabel>
{items.map((item) => (
<Combobox.Item key={item.value} item={item}>
<Combobox.ItemText>{item.label}</Combobox.ItemText>
<Combobox.ItemIndicator>✓</Combobox.ItemIndicator>
</Combobox.Item>
))}
</Combobox.ItemGroup>
</Combobox.Content>
</Combobox.Positioner>
</Portal>
</Combobox.Root>
)
}
import { For } from 'solid-js'
import { Portal } from 'solid-js/web'
import { Combobox } from '@ark-ui/solid'
export const Advanced = () => {
const items = [
{ label: 'React', value: 'react' },
{ label: 'Solid', value: 'solid' },
{ label: 'Vue', value: 'vue' },
{ label: 'Svelte', value: 'svelte', disabled: true },
]
return (
<Combobox.Root items={items}>
<Combobox.Label>Framework</Combobox.Label>
<Combobox.Control>
<Combobox.Input />
<Combobox.Trigger>Open</Combobox.Trigger>
<Combobox.ClearTrigger>Clear</Combobox.ClearTrigger>
</Combobox.Control>
<Portal>
<Combobox.Positioner>
<Combobox.Content>
<Combobox.ItemGroup>
<Combobox.ItemGroupLabel>Frameworks</Combobox.ItemGroupLabel>
<For each={items}>
{(item) => (
<Combobox.Item item={item}>
<Combobox.ItemText>{item.label}</Combobox.ItemText>
<Combobox.ItemIndicator>✓</Combobox.ItemIndicator>
</Combobox.Item>
)}
</For>
</Combobox.ItemGroup>
</Combobox.Content>
</Combobox.Positioner>
</Portal>
</Combobox.Root>
)
}
<script setup lang="ts">
import { ref } from 'vue'
import { Combobox } from '@ark-ui/vue'
const advancedItems = ref([
{ label: 'React', value: 'react' },
{ label: 'Solid', value: 'solid' },
{ label: 'Vue', value: 'vue' },
{ label: 'Svelte', value: 'svelte', disabled: true },
])
</script>
<template>
<Combobox.Root :items="advancedItems" multiple>
<Combobox.Label>Framework</Combobox.Label>
<Combobox.Control>
<Combobox.Input />
<Combobox.Trigger>Open</Combobox.Trigger>
<Combobox.ClearTrigger>Clear</Combobox.ClearTrigger>
</Combobox.Control>
<Teleport to="body">
<Combobox.Positioner>
<Combobox.Content>
<Combobox.ItemGroup>
<Combobox.ItemGroupLabel>Frameworks</Combobox.ItemGroupLabel>
<Combobox.Item v-for="item in advancedItems" :key="item.value" :item="item">
<Combobox.ItemText>{{ item.label }}</Combobox.ItemText>
<Combobox.ItemIndicator>✓</Combobox.ItemIndicator>
</Combobox.Item>
</Combobox.ItemGroup>
</Combobox.Content>
</Combobox.Positioner>
</Teleport>
</Combobox.Root>
</template>
TypeScript Caveats in Vue
Under the hood for React and Solid frameworks, we supply a complex prop type with a generic so that
the type of the items
prop matches the param type in the function signatures for props such as the
isItemDisabled
prop, say. (See the api reference table below) Unfortunately, generic typing is not
supported in Vue for components that contain props with slots and/or emits. Therefore, you will not
expect updated typing in this way.
If you have a solution or a workaround to this problem, we would love the contribution and request that you open a Github idea discussion to let us know a PoC you have to share!
API Reference
Root
Prop | Default | Type |
---|---|---|
items | T[] | readonly T[] The options of the select | |
allowCustomValue | boolean Whether to allow typing custom values in the input | |
asChild | boolean Render as a different element type. | |
autoFocus | boolean Whether to autofocus the input on mount | |
closeOnSelect | boolean Whether to close the combobox when an item is selected. | |
composite | true | boolean Whether the combobox is a composed with other composite widgets like tabs |
defaultOpen | boolean The initial open state of the combobox when it is first rendered. Use when you do not need to control its open state. | |
defaultValue | string[] The initial value of the combobox when it is first rendered. Use when you do not need to control the state of the combobox. | |
disabled | boolean Whether the combobox is disabled | |
disableLayer | boolean Whether to disable registering this a dismissable layer | |
form | string The associate form of the combobox. | |
getSelectionValue | (details: SelectionValueDetails<T>) => string Function to get the display value of the selected item | |
highlightedValue | string The active item's id. Used to set the `aria-activedescendant` attribute | |
id | string The unique identifier of the machine. | |
ids | Partial<{
root: string
label: string
control: string
input: string
content: string
trigger: string
clearTrigger: string
item(id: string, index?: number | undefined): string
positioner: string
itemGroup(id: string | number): string
itemGroupLabel(id: string | number): string
}> The ids of the elements in the combobox. Useful for composition. | |
inputBehavior | 'none' | 'none' | 'autohighlight' | 'autocomplete' Defines the auto-completion behavior of the combobox. - `autohighlight`: The first focused item is highlighted as the user types - `autocomplete`: Navigating the listbox with the arrow keys selects the item and the input is updated |
inputValue | string The current value of the combobox's input | |
invalid | boolean Whether the combobox is required | |
isItemDisabled | (item: T) => boolean Whether the item is disabled | |
itemToString | (item: T) => string The label of the item | |
itemToValue | (item: T) => string The value of the item | |
lazyMount | false | boolean Whether to enable lazy mounting |
loopFocus | true | boolean Whether to loop the keyboard navigation through the items |
multiple | boolean Whether to allow multiple selection | |
name | string The `name` attribute of the combobox's input. Useful for form submission | |
onExitComplete | () => void Function called when the animation ends in the closed state. | |
onFocusOutside | (event: FocusOutsideEvent) => void Function called when the focus is moved outside the component | |
onHighlightChange | (details: HighlightChangeDetails<T>) => void Function called when an item is highlighted using the pointer or keyboard navigation. | |
onInputValueChange | (details: InputValueChangeDetails) => void Function called when the input's value changes | |
onInteractOutside | (event: InteractOutsideEvent) => void Function called when an interaction happens outside the component | |
onOpenChange | (details: OpenChangeDetails) => void Function called when the popup is opened | |
onPointerDownOutside | (event: PointerDownOutsideEvent) => void Function called when the pointer is pressed down outside the component | |
onValueChange | (details: ValueChangeDetails<T>) => void Function called when a new item is selected | |
open | boolean Whether the combobox is open | |
openOnChange | true | boolean | ((details: InputValueChangeDetails) => boolean) Whether to show the combobox when the input value changes |
openOnClick | false | boolean Whether to open the combobox popup on initial click on the input |
openOnKeyPress | true | boolean Whether to open the combobox on arrow key press |
placeholder | string The placeholder text of the combobox's input | |
positioning | PositioningOptions The positioning options to dynamically position the menu | |
present | boolean Whether the node is present (controlled by the user) | |
readOnly | boolean Whether the combobox is readonly. This puts the combobox in a "non-editable" mode but the user can still interact with it | |
scrollToIndexFn | (details: ScrollToIndexDetails) => void Function to scroll to a specific index | |
selectionBehavior | 'replace' | 'replace' | 'clear' | 'preserve' The behavior of the combobox input when an item is selected - `replace`: The selected item string is set as the input value - `clear`: The input value is cleared - `preserve`: The input value is preserved |
translations | IntlTranslations Specifies the localized strings that identifies the accessibility elements and their states | |
unmountOnExit | false | boolean Whether to unmount on exit. |
value | string[] The keys of the selected items |
Data Attribute | Value |
---|---|
[data-scope] | combobox |
[data-part] | root |
[data-invalid] | Present when invalid |
[data-readonly] | Present when read-only |
ClearTrigger
Prop | Default | Type |
---|---|---|
asChild | boolean Render as a different element type. |
Content
Prop | Default | Type |
---|---|---|
asChild | boolean Render as a different element type. |
Data Attribute | Value |
---|---|
[data-scope] | combobox |
[data-part] | content |
[data-state] | "open" | "closed" |
Control
Prop | Default | Type |
---|---|---|
asChild | boolean Render as a different element type. |
Data Attribute | Value |
---|---|
[data-scope] | combobox |
[data-part] | control |
[data-state] | "open" | "closed" |
[data-focus] | Present when focused |
[data-disabled] | Present when disabled |
[data-invalid] | Present when invalid |
Input
Prop | Default | Type |
---|---|---|
asChild | boolean Render as a different element type. |
Data Attribute | Value |
---|---|
[data-scope] | combobox |
[data-part] | input |
[data-invalid] | Present when invalid |
[data-state] | "open" | "closed" |
ItemGroupLabel
Prop | Default | Type |
---|---|---|
asChild | boolean Render as a different element type. |
ItemGroup
Prop | Default | Type |
---|---|---|
asChild | boolean Render as a different element type. |
ItemIndicator
Prop | Default | Type |
---|---|---|
asChild | boolean Render as a different element type. |
Data Attribute | Value |
---|---|
[data-scope] | combobox |
[data-part] | item-indicator |
[data-state] | "checked" | "unchecked" |
Item
Prop | Default | Type |
---|---|---|
asChild | boolean Render as a different element type. | |
item | any The item to render | |
persistFocus | boolean Whether hovering outside should clear the highlighted state |
Data Attribute | Value |
---|---|
[data-scope] | combobox |
[data-part] | item |
[data-highlighted] | Present when highlighted |
[data-state] | "checked" | "unchecked" |
[data-disabled] | Present when disabled |
[data-value] |
ItemText
Prop | Default | Type |
---|---|---|
asChild | boolean Render as a different element type. |
Data Attribute | Value |
---|---|
[data-scope] | combobox |
[data-part] | item-text |
[data-disabled] | Present when disabled |
[data-highlighted] | Present when highlighted |
Label
Prop | Default | Type |
---|---|---|
asChild | boolean Render as a different element type. |
Data Attribute | Value |
---|---|
[data-scope] | combobox |
[data-part] | label |
[data-readonly] | Present when read-only |
[data-disabled] | Present when disabled |
[data-invalid] | Present when invalid |
[data-focus] | Present when focused |
Positioner
Prop | Default | Type |
---|---|---|
asChild | boolean Render as a different element type. |
Trigger
Prop | Default | Type |
---|---|---|
asChild | boolean Render as a different element type. | |
focusable | boolean Whether the trigger is focusable |
Data Attribute | Value |
---|---|
[data-scope] | combobox |
[data-part] | trigger |
[data-state] | "open" | "closed" |
[data-readonly] | Present when read-only |
[data-disabled] | Present when disabled |
Accessibility
Complies with the Combobox WAI-ARIA design pattern.
Keyboard Support
Key | Description |
---|---|
ArrowDown | When the combobox is closed, opens the listbox and highlights to the first option. When the combobox is open, moves focus to the next option. |
ArrowUp | When the combobox is closed, opens the listbox and highlights to the last option. When the combobox is open, moves focus to the previous option. |
Home | When the combobox is open, moves focus to the first option. |
End | When the combobox is open, moves focus to the last option. |
Escape | Closes the listbox. |
Enter | Selects the highlighted option and closes the combobox. |
Esc | Closes the combobox |