Skip to content
shadcn.io is not affiliated with official shadcn/ui

Shadcn Autocomplete for React and Tailwind

A searchable input that suggests options while allowing custom values.

Installation

bunx --bun shadcn@latest add https://kit.dev/r/autocomplete.json

Anatomy

Autocomplete
├── AutocompleteInput
│   ├── AutocompleteControl (built in)
│   ├── input
│   ├── AutocompleteTrigger (optional)
│   └── AutocompleteClear (optional)
└── AutocompleteContent
    ├── AutocompleteEmpty
    └── AutocompleteList
        └── AutocompleteGroup
            ├── AutocompleteGroupLabel
            └── AutocompleteItem

AutocompleteContent portals the list and includes the positioner. AutocompleteItem includes the check indicator.

Use Field for the visible label rather than a separate autocomplete label part.

Usage

Autocomplete is Combobox with allowCustomValue and inputBehavior="autocomplete". Pass a collection and filter as the user types.

import { useListCollection } from "@ark-ui/react/collection";
import { useFilter } from "@ark-ui/react/locale";
import {
  Autocomplete,
  AutocompleteContent,
  AutocompleteEmpty,
  AutocompleteGroup,
  AutocompleteInput,
  AutocompleteItem,
  AutocompleteList,
} from "@/components/ui/autocomplete";
const { contains } = useFilter({ sensitivity: "base" });
const { collection, filter } = useListCollection({
  initialItems: [
    { label: "Apple", value: "apple" },
    { label: "Banana", value: "banana" },
  ],
  filter: contains,
});

<Autocomplete
  collection={collection}
  onInputValueChange={({ inputValue }) => filter(inputValue)}
>
  <AutocompleteInput placeholder="e.g. Apple" />
  <AutocompleteContent>
    <AutocompleteEmpty />
    <AutocompleteList>
      {collection.items.map((item) => (
        <AutocompleteItem item={item} key={item.value}>
          {item.label}
        </AutocompleteItem>
      ))}
    </AutocompleteList>
  </AutocompleteContent>
</Autocomplete>

Controlled

Control the selected value with value and onValueChange. Selected values are always a string[].

Root Provider

Use useAutocomplete with AutocompleteRootProvider when you need the API outside the tree. Pass machine options (collection, allowCustomValue, inputBehavior, …) to useAutocomplete(), not to the provider.

States

Invalid

Disabled

Sizes

Size is set on AutocompleteInput. sm is h-7, md is h-8, lg is h-9.

Small

Medium

Large

Examples

Auto highlight

Highlight the first matching item as the user types with inputBehavior="autohighlight". This overrides Autocomplete’s default autocomplete behavior.

Inline autocomplete

Autocomplete already sets inputBehavior="autocomplete": arrow keys complete the input with the highlighted item. Pair it with a startsWith filter for best results.

Group

Group related items with groupBy on the collection and collection.group() when rendering. AutocompleteGroup accepts a heading for the label.

With Field

Field wires the label, helper text, and error text to the control.

Context

Read selected state with AutocompleteContext or useAutocompleteContext.

Render items as links with asChild. Use selectionBehavior="preserve" so choosing a link does not replace the input value.

Rehydrate

When defaultValue or value is set before the collection loads, call syncSelectedItems() once the items are available so the input shows the selected label.

Highlight text

Highlight the matching query in each item with Highlight.

Dynamic

Build the collection from the current input. Useful for email-style suggestions.

Creatable

Let users add a value that is not in the list. Upsert a temporary “create” item while typing, then replace it on select.

Multiple selection

Set multiple to select more than one item. Selection behavior becomes clear, so render selected items outside the input.

Load options from an async source with useAsyncList. Filter only on reason === "input-change" so highlighting and selection do not refetch.

Custom object

Map custom objects with itemToString and itemToValue on useListCollection.

Limit results

Pass limit to useListCollection to cap how many items are rendered.

With clear button

Pass showClear to AutocompleteInput. The clear control is shown when the input is not empty.

With trigger

Pass showTrigger to show the chevron that opens the list. Autocomplete hides it by default.

With start icon

Put an InputGroupAddon as a child of AutocompleteInput. Decorative icons should be aria-hidden="true".

Guides

Autocomplete vs Combobox

AutocompleteCombobox
Custom valuesAllowed (allowCustomValue)Closed list unless you opt in
Input behaviorautocompletenone
TriggerHidden (showTrigger={false})Shown
Use whenFree text with suggestionsPick from a known set, with search

Use Select when there is no search. Use Command for a command palette. Use Tags Input when the value is a list of removable tags.

Collections

Items live in an Ark collection, not a loose items prop on the root.

const { contains } = useFilter({ sensitivity: "base" });
const { collection, filter } = useListCollection({
  initialItems,
  filter: contains,
});

<Autocomplete
  collection={collection}
  onInputValueChange={({ inputValue }) => filter(inputValue)}
>

Call filter(inputValue) from onInputValueChange. Render collection.items (or collection.group() when grouping).

Custom objects

By default the collection expects { label, value }. Map other shapes with itemToString and itemToValue:

const { collection } = useListCollection({
  initialItems: [
    { country: "Canada", code: "CA", flag: "🇨🇦" },
  ],
  itemToString: (item) => item.country,
  itemToValue: (item) => item.code,
});

Type safety

Autocomplete is typed as Ark’s RootComponent, so onValueChange infers item types from the collection:

<Autocomplete
  collection={collection}
  onValueChange={(e) => {
    // e.items is T[]
    console.log(e.items);
  }}
>

Large datasets

Prefer limit on useListCollection so only a slice is in the DOM:

const { collection } = useListCollection({
  initialItems: items,
  limit: 10,
});

For very large lists, pass scrollToIndexFn and virtualize the list (for example with TanStack Virtual). Keyboard navigation needs that scroll helper.

Set navigate on the root when items are links, so in-app routing runs instead of a full navigation:

<Autocomplete
  collection={collection}
  navigate={(details) => {
    router.push(details.node.href);
  }}
>

NavigateDetails is { value: string; node: HTMLAnchorElement; href: string }.

Available size

The positioner (built into AutocompleteContent) exposes CSS variables you can use on the list:

CSS variableDescription
--reference-widthWidth of the input control
--reference-heightHeight of the root
--available-widthAvailable width in the viewport
--available-heightAvailable height in the viewport

Example: match the input width and cap height to the viewport.

<AutocompleteContent className="w-(--reference-width) max-h-[min(24rem,calc(var(--available-height)-100px))]" />

Multiple selection

When multiple is true, selectionBehavior is set to clear. Render selectedItems from context above the input (chips, tags, or a summary). Do not rely on the input to show every selected value.

API Reference

shadcn.io wraps Ark UI Combobox. Defaults below are shadcn.io Autocomplete values. They differ from Ark Combobox for allowCustomValue (true here), inputBehavior (autocomplete here, none in Ark), openOnClick (true here, false in Ark), and lazyMount / unmountOnExit (true here, false in Ark).

asChild merges props onto a single child element.

Autocomplete

Root. Renders a div. Requires a collection.

PropTypeDefaultDescription
collectionListCollection<T>requiredItems to show. Create with useListCollection or createListCollection.
allowCustomValuebooleantrueAllow values that are not in the collection.
alwaysSubmitOnEnterbooleanfalseSubmit on Enter even if the list is open. Useful for single-field forms.
asChildbooleanfalseRender the child element instead of a div.
autoFocusboolean-Focus the input on mount.
classNamestring-Class names on the root.
closeOnSelectboolean-Close the list when an item is selected.
compositebooleantrueTreat as composed with other composite widgets such as tabs.
defaultHighlightedValuestring-Uncontrolled initial highlighted value.
defaultInputValuestring""Uncontrolled initial input text.
defaultOpenboolean-Uncontrolled initial open state.
defaultValuestring[][]Uncontrolled selected values.
disabledboolean-Disable the autocomplete.
disableLayerboolean-Do not register as a dismissable layer.
formstring-Associated form id.
hideMode"display-none" | "activity""display-none"How to hide mounted-but-closed content. activity needs React 19+.
highlightedValuestring-Controlled highlighted value.
idstring-Unique id for the machine.
idsPartial<{ root: string; label: string; control: string; input: string; content: string; trigger: string; clearTrigger: string; item: (id: string, index?: number) => string; positioner: string; itemGroup: (id: string | number) => string; itemGroupLabel: (id: string | number) => string }>-Element ids for composition.
immediateboolean-Apply presence changes immediately instead of the next frame.
inputBehavior"none" | "autocomplete" | "autohighlight""autocomplete"autocomplete fills the input from the highlighted item. autohighlight highlights the first match while typing.
inputValuestring-Controlled input text.
invalidboolean-Mark as invalid.
lazyMountbooleantrueMount the list on first open.
loopFocusbooleantrueLoop keyboard focus through items.
multipleboolean-Allow more than one selected value. Forces selectionBehavior to clear.
namestring-name on the input for form submission.
navigate(details: NavigateDetails) => void-Called when a link item is chosen. { value, node, href }.
onExitComplete() => void-Called when the close animation finishes.
onFocusOutside(event: FocusOutsideEvent) => void-Called when focus moves outside.
onHighlightChange(details: HighlightChangeDetails<T>) => void-Called when the highlighted item changes. { highlightedValue, highlightedItem }.
onInputValueChange(details: InputValueChangeDetails) => void-Called when the input text changes. { inputValue, reason }. Filter the collection here.
onInteractOutside(event: InteractOutsideEvent) => void-Called on outside interaction.
onOpenChange(details: OpenChangeDetails) => void-Called when open state changes. { open, reason, value }.
onPointerDownOutside(event: PointerDownOutsideEvent) => void-Called on pointer down outside.
onSelect(details: SelectionDetails) => void-Called when an item is selected. { value, itemValue }.
onValueChange(details: ValueChangeDetails<T>) => void-Called when the selection changes. { value: string[]; items: T[] }.
openboolean-Controlled open state.
openOnChangeboolean | ((details: InputValueChangeDetails) => boolean)trueOpen the list when the input value changes.
openOnClickbooleantrueOpen the list on click in the input.
openOnKeyPressbooleantrueOpen the list on arrow keys.
placeholderstring-Placeholder on the root. Prefer placeholder on AutocompleteInput.
positioningPositioningOptions{ placement: "bottom-start" }Floating position of the list.
presentboolean-Controlled presence.
readOnlyboolean-Non-editable, but still interactive.
requiredboolean-Mark as required.
scrollToIndexFn(details: ScrollToIndexDetails) => void-Scroll a virtualized list to an index. { index, immediate, getElement }.
selectionBehavior"clear" | "replace" | "preserve""replace"After select: clear the input, replace it with the item, or leave it. multiple forces clear.
skipAnimationOnMountbooleanfalseSkip the initial presence animation.
translationsIntlTranslations-{ triggerLabel?, clearTriggerLabel? } for assistive labels.
unmountOnExitbooleantrueUnmount the list after the close animation.
valuestring[]-Controlled selected values.
AttributeDescription
data-slotautocomplete
data-scopecombobox
data-partroot
data-invalidPresent when invalid
data-readonlyPresent when read-only

AutocompleteInput

Composed control: Input Group wrapping the searchable input, optional trigger, and optional clear button. Children render as start addons (icons, text). Renders inside AutocompleteControl.

PropTypeDefaultDescription
size"sm" | "md" | "lg""md"Control height. sm is h-7, md is h-8, lg is h-9.
showTriggerbooleanfalseShow the chevron that opens the list. Hidden while the clear button is visible.
showClearbooleanfalseShow a clear button when inputValue is not empty.
placeholderstring-Placeholder on the input.
disabledboolean-Disable the input.
classNamestring-Class names on the input group.
asChildbooleanfalseMerge onto the underlying input.

Native input attributes (type, aria-label, autoComplete, …) pass through to the input.

The composed control is Combobox’s input group, so the wrapper keeps Combobox slots (combobox-control, combobox-trigger, combobox-clear). The input itself is autocomplete-input.

AttributeDescription
data-slotautocomplete-input on the input
data-scopecombobox
data-partinput
data-invalidPresent when invalid
data-state"open" or "closed"
data-autofocusPresent when autoFocus is set

AutocompleteControl

Optional wrapper for custom layouts. AutocompleteInput already includes it.

PropTypeDefaultDescription
asChildbooleanfalseMerge onto a single child.
classNamestring-Class names on the control.
AttributeDescription
data-slotautocomplete-control
data-scopecombobox
data-partcontrol
data-state"open" or "closed"
data-focusPresent when focused
data-disabledPresent when disabled
data-invalidPresent when invalid

AutocompleteTrigger

Opens the list. Used by AutocompleteInput when showTrigger is true. Renders a button.

PropTypeDefaultDescription
asChildbooleanfalseMerge onto a single child.
classNamestring-Class names on the trigger.
focusableboolean-Whether the trigger is in the tab order.
AttributeDescription
data-slotautocomplete-trigger
data-scopecombobox
data-parttrigger
data-state"open" or "closed"
data-invalidPresent when invalid
data-readonlyPresent when read-only
data-disabledPresent when disabled
data-focusablePresent when focusable

AutocompleteClear

Clears the input. Used by AutocompleteInput when showClear is true. Renders a button.

PropTypeDefaultDescription
asChildbooleanfalseMerge onto a single child.
classNamestring-Class names on the clear control.
AttributeDescription
data-slotautocomplete-clear
data-scopecombobox
data-partclear-trigger
data-invalidPresent when invalid

AutocompleteContent

Portaled list surface. Includes the positioner. Renders a div.

PropTypeDefaultDescription
asChildbooleanfalseMerge onto a single child.
classNamestring-Class names on the content.
AttributeDescription
data-slotautocomplete-content
data-scopecombobox
data-partcontent
data-state"open" or "closed"
data-placementPlacement of the content
data-sideSide of the trigger the content is on
data-emptyPresent when there are no items
data-nestedPresent when nested in another listbox
data-has-nestedPresent when this list has nested listboxes
CSS variableDescription
--layer-indexIndex in the dismissable layer stack
--nested-layer-countNumber of nested comboboxes
--transform-originTransform origin for open/close animation
--reference-widthWidth of the input control (on the positioner)
--reference-heightHeight of the root (on the positioner)
--available-widthAvailable width in the viewport (on the positioner)
--available-heightAvailable height in the viewport (on the positioner)

AutocompleteList

Wraps the options. Renders a div.

PropTypeDefaultDescription
asChildbooleanfalseMerge onto a single child.
classNamestring-Class names on the list.
AttributeDescription
data-slotautocomplete-list
data-scopecombobox
data-partlist
data-emptyPresent when there are no items

AutocompleteItem

A single option. Always uses persistFocus so pointer leave does not clear highlight. Includes a check indicator unless showIndicator={false}. Renders a div.

PropTypeDefaultDescription
itemTrequiredCollection item.
showIndicatorbooleantrueShow the selected check.
asChildbooleanfalseMerge onto a single child (for example an <a>).
classNamestring-Class names on the item.
persistFocusbooleantrueKeep highlight when the pointer leaves.
AttributeDescription
data-slotautocomplete-item
data-scopecombobox
data-partitem
data-highlightedPresent when highlighted
data-state"checked" or "unchecked"
data-disabledPresent when disabled
data-valueThe item value

The indicator is not a separate export.

AttributeDescription
data-slotcombobox-item-indicator
data-scopecombobox
data-partitem-indicator
data-state"checked" or "unchecked"

AutocompleteGroup

Groups related options. Pass heading to render AutocompleteGroupLabel.

PropTypeDefaultDescription
headingstring | ReactNode-Group label.
idstring-Group id.
asChildbooleanfalseMerge onto a single child.
classNamestring-Class names on the group.
AttributeDescription
data-slotautocomplete-group
data-scopecombobox
data-partitem-group
data-emptyPresent when the group is empty

AutocompleteGroupLabel

Label for a group. Usually created by heading on AutocompleteGroup. Renders a div.

PropTypeDefaultDescription
asChildbooleanfalseMerge onto a single child.
classNamestring-Class names on the label.
AttributeDescription
data-slotautocomplete-group-label
data-scopecombobox
data-partitem-group-label

AutocompleteEmpty

Shown when the filtered collection has no items. Default children: No results found.

PropTypeDefaultDescription
asChildbooleanfalseMerge onto a single child.
classNamestring-Class names on the empty state.
childrenReactNodeNo results found.Empty message.
AttributeDescription
data-slotautocomplete-empty
data-scopecombobox
data-partempty

AutocompleteSeparator

Separator for custom list layouts.

PropTypeDefaultDescription
classNamestring-Class names on the separator.
AttributeDescription
data-slotautocomplete-separator

AutocompleteRootProvider

Root alternative that takes the API from useAutocomplete. Renders a div.

PropTypeDefaultDescription
valueUseComboboxReturn<T>requiredReturn value of useAutocomplete().
asChildbooleanfalseRender the child element instead of a div.
hideMode"display-none" | "activity""display-none"How to hide mounted-but-closed content.
immediateboolean-Apply presence changes immediately.
lazyMountbooleantrueMount the list on first open.
onExitComplete() => void-Called when the close animation finishes.
presentboolean-Controlled presence.
skipAnimationOnMountbooleanfalseSkip the initial presence animation.
unmountOnExitbooleantrueUnmount after the close animation.

Pass collection, allowCustomValue, inputBehavior, and other machine options to useAutocomplete(), not to AutocompleteRootProvider. To match Autocomplete, pass allowCustomValue: true and inputBehavior: "autocomplete".

AttributeDescription
data-slotautocomplete
data-scopecombobox
data-partroot

useAutocomplete

Creates the autocomplete API for AutocompleteRootProvider. Accepts the same options as Autocomplete except layout-only props.

const autocomplete = useAutocomplete({
  allowCustomValue: true,
  collection,
  inputBehavior: "autocomplete",
  onInputValueChange: (details) => filter(details.inputValue),
});

autocomplete.focus();

AutocompleteContext / useAutocompleteContext

Render-prop or hook access to autocomplete state. Use inside Autocomplete or AutocompleteRootProvider.

PropertyTypeDescription
focusedbooleanWhether the input is focused.
openbooleanWhether the list is open.
inputValuestringCurrent input text.
highlightedValuestring | nullValue of the highlighted item.
highlightedItemT | nullHighlighted item.
setHighlightValue(value: string) => voidHighlight an item by value.
clearHighlightValue() => voidClear the highlight.
syncSelectedItems() => voidSync selected items after an async collection load.
selectedItemsT[]Selected items.
hasSelectedItemsbooleanWhether any item is selected.
valuestring[]Selected values.
valueAsStringstringSelected items as a string.
selectValue(value: string) => voidSelect a value.
setValue(value: string[]) => voidSet the selection.
clearValue(value?: string) => voidClear one value, or all if omitted.
focus() => voidFocus the input.
setInputValue(value: string, reason?: InputValueChangeReason) => voidSet the input text.
getItemState(props: { item: T; persistFocus?: boolean }) => ItemStateState for one item (value, disabled, selected, highlighted).
setOpen(open: boolean, reason?: OpenChangeReason) => voidOpen or close the list.
collectionListCollection<T>Current collection.
reposition(options?: Partial<PositioningOptions>) => voidUpdate list position.
multiplebooleanWhether multiple selection is on.
disabledbooleanWhether the autocomplete is disabled.

AutocompleteContext children: (context) => ReactNode.

Accessibility

Complies with the Combobox WAI-ARIA design pattern. Label the input with Field (FieldLabel) or aria-label on AutocompleteInput. Keep AutocompleteEmpty so a filtered list is not a blank popup.

Keyboard support

KeyDescription
ArrowDownWhen closed, opens the list and highlights the first option. When open, moves to the next option.
ArrowUpWhen closed, opens the list and highlights the last option. When open, moves to the previous option.
HomeWhen open, moves to the first option.
EndWhen open, moves to the last option.
EnterSelects the highlighted option and closes the list.
EscapeCloses the list.