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-partattribute 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
Root
| Prop | Default | Type | 
|---|---|---|
| collection | ListCollection<T>The collection of items | |
| allowCustomValue | booleanWhether to allow typing custom values in the input | |
| asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior.For more details, read our Composition guide. | |
| autoFocus | booleanWhether to autofocus the input on mount | |
| closeOnSelect | booleanWhether to close the combobox when an item is selected. | |
| composite | true | booleanWhether the combobox is a composed with other composite widgets like tabs | 
| defaultOpen | booleanThe 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 | booleanWhether the combobox is disabled | |
| disableLayer | booleanWhether to disable registering this a dismissable layer | |
| form | stringThe associate form of the combobox. | |
| getSelectionValue | (details: SelectionValueDetails<T>) => stringFunction to get the display value of the selected item | |
| highlightedValue | stringThe active item's id. Used to set the `aria-activedescendant` attribute | |
| id | stringThe 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. | |
| immediate | booleanWhether to synchronize the present change immediately or defer it to the next frame | |
| 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 | stringThe current value of the combobox's input | |
| invalid | booleanWhether the combobox is invalid | |
| lazyMount | false | booleanWhether to enable lazy mounting | 
| loopFocus | true | booleanWhether to loop the keyboard navigation through the items | 
| multiple | booleanWhether to allow multiple selection. **Good to know:** When `multiple` is `true`, the `selectionBehavior` is automatically set to `clear`. It is recommended to render the selected items in a separate container. | |
| name | stringThe `name` attribute of the combobox's input. Useful for form submission | |
| onExitComplete | () => voidFunction called when the animation ends in the closed state | |
| onFocusOutside | (event: FocusOutsideEvent) => voidFunction called when the focus is moved outside the component | |
| onHighlightChange | (details: HighlightChangeDetails<T>) => voidFunction called when an item is highlighted using the pointer or keyboard navigation. | |
| onInputValueChange | (details: InputValueChangeDetails) => voidFunction called when the input's value changes | |
| onInteractOutside | (event: InteractOutsideEvent) => voidFunction called when an interaction happens outside the component | |
| onOpenChange | (details: OpenChangeDetails) => voidFunction called when the popup is opened | |
| onPointerDownOutside | (event: PointerDownOutsideEvent) => voidFunction called when the pointer is pressed down outside the component | |
| onValueChange | (details: ValueChangeDetails<T>) => voidFunction called when a new item is selected | |
| open | booleanWhether the combobox is open | |
| openOnChange | true | boolean | ((details: InputValueChangeDetails) => boolean)Whether to show the combobox when the input value changes | 
| openOnClick | false | booleanWhether to open the combobox popup on initial click on the input | 
| openOnKeyPress | true | booleanWhether to open the combobox on arrow key press | 
| placeholder | stringThe placeholder text of the combobox's input | |
| positioning | PositioningOptionsThe positioning options to dynamically position the menu | |
| present | booleanWhether the node is present (controlled by the user) | |
| readOnly | booleanWhether the combobox is readonly. This puts the combobox in a "non-editable" mode but the user can still interact with it | |
| required | booleanWhether the combobox is required | |
| scrollToIndexFn | (details: ScrollToIndexDetails) => voidFunction 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 | IntlTranslationsSpecifies the localized strings that identifies the accessibility elements and their states | |
| unmountOnExit | false | booleanWhether 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 | booleanUse the provided child element as the default rendered element, combining their props and behavior.For more details, read our Composition guide. | 
| Data Attribute | Value | 
|---|---|
| [data-scope] | combobox | 
| [data-part] | clear-trigger | 
| [data-invalid] | Present when invalid | 
Content
| Prop | Default | Type | 
|---|---|---|
| asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior.For more details, read our Composition guide. | 
| Data Attribute | Value | 
|---|---|
| [data-scope] | combobox | 
| [data-part] | content | 
| [data-state] | "open" | "closed" | 
| [data-placement] | The placement of the content | 
Control
| Prop | Default | Type | 
|---|---|---|
| asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior.For more details, read our Composition guide. | 
| 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 | booleanUse the provided child element as the default rendered element, combining their props and behavior.For more details, read our Composition guide. | 
| Data Attribute | Value | 
|---|---|
| [data-scope] | combobox | 
| [data-part] | input | 
| [data-invalid] | Present when invalid | 
| [data-state] | "open" | "closed" | 
ItemGroupLabel
| Prop | Default | Type | 
|---|---|---|
| asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior.For more details, read our Composition guide. | 
ItemGroup
| Prop | Default | Type | 
|---|---|---|
| asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior.For more details, read our Composition guide. | 
ItemIndicator
| Prop | Default | Type | 
|---|---|---|
| asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior.For more details, read our Composition guide. | 
| Data Attribute | Value | 
|---|---|
| [data-scope] | combobox | 
| [data-part] | item-indicator | 
| [data-state] | "checked" | "unchecked" | 
Item
| Prop | Default | Type | 
|---|---|---|
| asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior.For more details, read our Composition guide. | |
| item | anyThe item to render | |
| persistFocus | booleanWhether 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 | booleanUse the provided child element as the default rendered element, combining their props and behavior.For more details, read our Composition guide. | 
| Data Attribute | Value | 
|---|---|
| [data-scope] | combobox | 
| [data-part] | item-text | 
| [data-state] | "checked" | "unchecked" | 
| [data-disabled] | Present when disabled | 
| [data-highlighted] | Present when highlighted | 
Label
| Prop | Default | Type | 
|---|---|---|
| asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior.For more details, read our Composition guide. | 
| 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 | 
List
| Prop | Default | Type | 
|---|---|---|
| asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior.For more details, read our Composition guide. | 
Positioner
| Prop | Default | Type | 
|---|---|---|
| asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior.For more details, read our Composition guide. | 
RootProvider
| Prop | Default | Type | 
|---|---|---|
| value | UseComboboxReturn<T> | |
| asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior.For more details, read our Composition guide. | |
| immediate | booleanWhether to synchronize the present change immediately or defer it to the next frame | |
| lazyMount | false | booleanWhether to enable lazy mounting | 
| onExitComplete | () => voidFunction called when the animation ends in the closed state | |
| present | booleanWhether the node is present (controlled by the user) | |
| unmountOnExit | false | booleanWhether to unmount on exit. | 
Trigger
| Prop | Default | Type | 
|---|---|---|
| asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior.For more details, read our Composition guide. | |
| focusable | booleanWhether the trigger is focusable | 
| Data Attribute | Value | 
|---|---|
| [data-scope] | combobox | 
| [data-part] | trigger | 
| [data-state] | "open" | "closed" | 
| [data-invalid] | Present when invalid | 
| [data-focusable] | |
| [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 |