Combobox
A single input field that combines the functionality of a select and input.
Frameworks
React
Solid
Vue
Svelte
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 { useMemo, useState } from 'react'
import { Combobox, Portal, createListCollection } from '@ark-ui/react'
const initialItems = ['React', 'Solid', 'Vue']
export const Basic = () => {
const [items, setItems] = useState(initialItems)
const collection = useMemo(() => createListCollection({ items }), [items])
const handleInputChange = (details: Combobox.InputValueChangeDetails) => {
setItems(
initialItems.filter((item) => item.toLowerCase().includes(details.inputValue.toLowerCase())),
)
}
return (
<Combobox.Root collection={collection} onInputValueChange={handleInputChange}>
<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>
{collection.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, createMemo, createSignal } from 'solid-js'
import { Portal } from 'solid-js/web'
import { Combobox, createListCollection } from '@ark-ui/solid'
const initialItems = ['React', 'Solid', 'Vue']
export const Basic = () => {
const [items, setItems] = createSignal(initialItems)
const collection = createMemo(() => createListCollection({ items: items() }))
const handleInputChange = (details: Combobox.InputValueChangeDetails) => {
setItems(
initialItems.filter((item) => item.toLowerCase().includes(details.inputValue.toLowerCase())),
)
}
return (
<Combobox.Root collection={collection()} onInputValueChange={handleInputChange}>
<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={collection().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 { computed, ref } from 'vue'
// biome-ignore lint/style/useImportType: <explanation>
import { Combobox, createListCollection } from '@ark-ui/vue'
const initialItems = ['React', 'Solid', 'Vue']
const items = ref(initialItems)
const collection = computed(() => createListCollection({ items: items.value }))
const handleInputChange = (details: Combobox.InputValueChangeDetails) => {
items.value = initialItems.filter((item) =>
item.toLowerCase().includes(details.inputValue.toLowerCase()),
)
}
</script>
<template>
<Combobox.Root :collection="collection" @input-value-change="handleInputChange">
<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 collection.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, createListCollection } from '@ark-ui/react'
export const Advanced = () => {
const collection = createListCollection({
items: [
{ label: 'React', value: 'react' },
{ label: 'Solid', value: 'solid' },
{ label: 'Vue', value: 'vue' },
{ label: 'Svelte', value: 'svelte', disabled: true },
],
})
return (
<Combobox.Root collection={collection} 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>
{collection.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, createListCollection } from '@ark-ui/solid'
export const Advanced = () => {
const collection = createListCollection({
items: [
{ label: 'React', value: 'react' },
{ label: 'Solid', value: 'solid' },
{ label: 'Vue', value: 'vue' },
{ label: 'Svelte', value: 'svelte', disabled: true },
],
})
return (
<Combobox.Root collection={collection}>
<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={collection.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 { Combobox, createListCollection } from '@ark-ui/vue'
const frameworks = createListCollection({
items: [
{ label: 'React', value: 'react' },
{ label: 'Solid', value: 'solid' },
{ label: 'Vue', value: 'vue' },
{ label: 'Svelte', value: 'svelte', disabled: true },
],
})
</script>
<template>
<Combobox.Root :collection="frameworks" 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 frameworks.items" :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>
Using the Field Component
The Field
component helps manage form-related state and accessibility attributes of a combobox.
It includes handling ARIA labels, helper text, and error text to ensure proper accessibility.
import { Combobox, Field, createListCollection } from '@ark-ui/react'
export const WithField = (props: Field.RootProps) => {
const collection = createListCollection({ items: ['React', 'Solid', 'Vue'] })
return (
<Field.Root {...props}>
<Combobox.Root collection={collection}>
<Combobox.Label>Label</Combobox.Label>
<Combobox.Control>
<Combobox.Input />
<Combobox.Trigger>Open</Combobox.Trigger>
<Combobox.ClearTrigger>Clear</Combobox.ClearTrigger>
</Combobox.Control>
<Combobox.Positioner>
<Combobox.Content>
{collection.items.map((item) => (
<Combobox.Item key={item} item={item}>
<Combobox.ItemText>{item}</Combobox.ItemText>
<Combobox.ItemIndicator>✓</Combobox.ItemIndicator>
</Combobox.Item>
))}
</Combobox.Content>
</Combobox.Positioner>
</Combobox.Root>
<Field.HelperText>Additional Info</Field.HelperText>
<Field.ErrorText>Error Info</Field.ErrorText>
</Field.Root>
)
}
import { For } from 'solid-js'
import { Combobox, Field, createListCollection } from '@ark-ui/solid'
export const WithField = (props: Field.RootProps) => {
const collection = createListCollection({ items: ['React', 'Solid', 'Vue'] })
return (
<Field.Root {...props}>
<Combobox.Root collection={collection}>
<Combobox.Label>Label</Combobox.Label>
<Combobox.Control>
<Combobox.Input />
<Combobox.Trigger>Open</Combobox.Trigger>
<Combobox.ClearTrigger>Clear</Combobox.ClearTrigger>
</Combobox.Control>
<Combobox.Positioner>
<Combobox.Content>
<For each={collection.items}>
{(item) => (
<Combobox.Item item={item}>
<Combobox.ItemText>{item}</Combobox.ItemText>
<Combobox.ItemIndicator>✓</Combobox.ItemIndicator>
</Combobox.Item>
)}
</For>
</Combobox.Content>
</Combobox.Positioner>
</Combobox.Root>
<Field.HelperText>Additional Info</Field.HelperText>
<Field.ErrorText>Error Info</Field.ErrorText>
</Field.Root>
)
}
<script setup lang="ts">
import { Combobox, Field, createListCollection } from '@ark-ui/vue'
const frameworks = createListCollection({
items: ['React', 'Solid', 'Vue'],
})
</script>
<template>
<Field.Root>
<Combobox.Root :collection="frameworks">
<Combobox.Label>Label</Combobox.Label>
<Combobox.Control>
<Combobox.Input />
<Combobox.Trigger>Open</Combobox.Trigger>
<Combobox.ClearTrigger>Clear</Combobox.ClearTrigger>
</Combobox.Control>
<Combobox.Positioner>
<Combobox.Content>
<Combobox.ItemGroup>
<Combobox.ItemGroupLabel>Frameworks</Combobox.ItemGroupLabel>
<Combobox.Item v-for="item in frameworks.items" :key="item" :item="item">
<Combobox.ItemText>{{ item }}</Combobox.ItemText>
<Combobox.ItemIndicator>✓</Combobox.ItemIndicator>
</Combobox.Item>
</Combobox.ItemGroup>
</Combobox.Content>
</Combobox.Positioner>
</Combobox.Root>
<Field.HelperText>Additional Info</Field.HelperText>
<Field.ErrorText>Error Info</Field.ErrorText>
</Field.Root>
</template>
API Reference
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 |