Reka UI logoReka
backdrop
Components

Autocomplete

Alpha
An input with suggestions that allows free-form text entry. Unlike Combobox, the value is the input text itself rather than a selected item.

Features

  • Can be controlled or uncontrolled.
  • Offers 2 positioning modes.
  • Supports items, labels, groups of items.
  • Focus is fully managed.
  • Full keyboard navigation.
  • Supports custom placeholder.
  • Supports Right to Left direction.
  • Free-form text input — value is the typed text, not a selection.

Installation

Install the component from your command line.

sh
$ npm add reka-ui

Anatomy

Import all parts and piece them together.

vue
<script setup lang="ts">
import {
  AutocompleteAnchor,
  AutocompleteArrow,
  AutocompleteCancel,
  AutocompleteContent,
  AutocompleteEmpty,
  AutocompleteGroup,
  AutocompleteInput,
  AutocompleteItem,
  AutocompleteLabel,
  AutocompletePortal,
  AutocompleteRoot,
  AutocompleteSeparator,
  AutocompleteTrigger,
  AutocompleteViewport,
} from 'reka-ui'
</script>

<template>
  <AutocompleteRoot>
    <AutocompleteAnchor>
      <AutocompleteInput />
      <AutocompleteTrigger />
      <AutocompleteCancel />
    </AutocompleteAnchor>

    <AutocompletePortal>
      <AutocompleteContent>
        <AutocompleteViewport>
          <AutocompleteEmpty />

          <AutocompleteItem />

          <AutocompleteSeparator />

          <AutocompleteGroup>
            <AutocompleteLabel />
            <AutocompleteItem />
          </AutocompleteGroup>
        </AutocompleteViewport>

        <AutocompleteArrow />
      </AutocompleteContent>
    </AutocompletePortal>
  </AutocompleteRoot>
</template>

Autocomplete vs. Combobox

The Autocomplete component is similar to the Combobox but with a key difference:

AutocompleteCombobox
modelValueThe input text (string)The selected item (AcceptableValue)
Free-form textYes — any text is validNo — must select from the list
multipleNot supportedSupported
Input on blurRetains typed text by defaultResets to selected value by default
Item selectionFills the input with the item's text valueSets modelValue to the item's value

Use Autocomplete when the user should be able to type anything with optional suggestions. Use Combobox when the user must pick from a predefined set of options.

API Reference

Root

Contains all the parts of an Autocomplete.

PropDefaultType
as
'div'
AsTag | Component

The element or component this component should render as. Can be overwritten by asChild.

asChild
boolean

Change the default rendered element for the one passed as a child, merging their props and behavior.

Read our Composition guide for more details.

defaultOpen
boolean

The open state of the autocomplete when it is initially rendered. Use when you do not need to control its open state.

defaultValue
string

The value of the autocomplete when initially rendered. Use when you do not need to control the state.

dir
'ltr' | 'rtl'

The reading direction of the autocomplete when applicable.

disabled
boolean

When true, prevents the user from interacting with autocomplete

highlightOnHover
true
boolean

When true, hover over item will trigger highlight

ignoreFilter
boolean

When true, disable the default filters

modelValue
string

The controlled value of the Autocomplete (the input text). Can be bound with v-model.

name
string

The name of the field. Submitted with its owning form as part of a name/value pair.

open
boolean

The controlled open state of the Autocomplete. Can be bound with v-model:open.

openOnClick
false
boolean

Whether to open the autocomplete when the input is clicked

openOnFocus
false
boolean

Whether to open the autocomplete when the input is focused

required
boolean

When true, indicates that the user must set the value before the owning form can be submitted.

resetSearchTermOnBlur
false
boolean

Whether to reset the searchTerm when the Autocomplete input blurred

EmitPayload
highlight
[payload: { ref: HTMLElement; value: string; }]

Event handler when highlighted element changes.

update:modelValue
[value: string]

Event handler called when the value changes.

update:open
[value: boolean]

Event handler called when the open state of the autocomplete changes.

Slots (default)Payload
open
boolean

Current open state

modelValue
string

Current active value

Anchor

Used as an anchor if you set AutocompleteContent's position to popper.

PropDefaultType
as
'div'
AsTag | Component

The element or component this component should render as. Can be overwritten by asChild.

asChild
boolean

Change the default rendered element for the one passed as a child, merging their props and behavior.

Read our Composition guide for more details.

reference
ReferenceElement

The reference (or anchor) element that is being referred to for positioning.

If not provided will use the current component as anchor.

Input

The input component to search through the autocomplete items. Typing updates the modelValue directly.

PropDefaultType
as
'input'
AsTag | Component

The element or component this component should render as. Can be overwritten by asChild.

asChild
boolean

Change the default rendered element for the one passed as a child, merging their props and behavior.

Read our Composition guide for more details.

autoFocus
boolean

Focus on element when mounted.

disabled
boolean

When true, prevents the user from interacting with item

modelValue
string

The controlled value of the filter. Can be binded with v-model.

EmitPayload
update:modelValue
[string]

Event handler called when the value changes.

Trigger

The button that toggles the Autocomplete Content.

PropDefaultType
as
'button'
AsTag | Component

The element or component this component should render as. Can be overwritten by asChild.

asChild
boolean

Change the default rendered element for the one passed as a child, merging their props and behavior.

Read our Composition guide for more details.

disabled
boolean

When true, prevents the user from interacting with item

Data AttributeValue
[data-state]"open" | "closed"
[data-disabled]Present when disabled

Cancel

The button that clears the input text and resets the value.

PropDefaultType
as
'button'
AsTag | Component

The element or component this component should render as. Can be overwritten by asChild.

asChild
boolean

Change the default rendered element for the one passed as a child, merging their props and behavior.

Read our Composition guide for more details.

Empty

Shown when none of the items match the query.

PropDefaultType
as
'div'
AsTag | Component

The element or component this component should render as. Can be overwritten by asChild.

asChild
boolean

Change the default rendered element for the one passed as a child, merging their props and behavior.

Read our Composition guide for more details.

Portal

When used, portals the content part into the body.

You need to set position="popper" for AutocompleteContent to make sure the position was automatically computed similar to Popover or DropdownMenu.

PropDefaultType
defer
boolean

Defer the resolving of a Teleport target until other parts of the application have mounted (requires Vue 3.5.0+)

reference

disabled
boolean

Disable teleport and render the component inline

reference

forceMount
boolean

Used to force mounting when more control is needed. Useful when controlling animation with Vue animation libraries.

to
string | HTMLElement

Vue native teleport component prop :to

reference

Content

The component that pops out when the autocomplete is open.

tip
Built with Presence component - supports any animation techniques while maintaining access to presence emitted events.
PropDefaultType
align
'start' | 'center' | 'end'

The preferred alignment against the trigger. May change when collisions occur.

alignFlip
boolean

Flip alignment when colliding with boundary. May only occur when prioritizePosition is true.

alignOffset
number

An offset in pixels from the start or end alignment options.

arrowPadding
number

The padding between the arrow and the edges of the content. If your content has border-radius, this will prevent it from overflowing the corners.

as
'div'
AsTag | Component

The element or component this component should render as. Can be overwritten by asChild.

asChild
boolean

Change the default rendered element for the one passed as a child, merging their props and behavior.

Read our Composition guide for more details.

avoidCollisions
boolean

When true, overrides the side and align preferences to prevent collisions with boundary edges.

bodyLock
boolean

The document.body will be lock, and scrolling will be disabled.

collisionBoundary
Element | (Element | null)[] | null

The element used as the collision boundary. By default this is the viewport, though you can provide additional element(s) to be included in this check.

collisionPadding
number | Partial<Record<'top' | 'right' | 'bottom' | 'left', number>>

The distance in pixels from the boundary edges where collision detection should occur. Accepts a number (same for all sides), or a partial padding object, for example: { top: 20, left: 20 }.

disableOutsidePointerEvents
boolean

When true, hover/focus/click interactions will be disabled on elements outside the DismissableLayer. Users will need to click twice on outside elements to interact with them: once to close the DismissableLayer, and again to trigger the element.

disableUpdateOnLayoutShift
boolean

Whether to disable the update position for the content when the layout shifted.

forceMount
boolean

Used to force mounting when more control is needed. Useful when controlling animation with Vue animation libraries.

hideShiftedArrow
boolean

When true, hides the arrow when it cannot be centered to the reference element.

hideWhenDetached
boolean

Whether to hide the content when the trigger becomes fully occluded.

hideWhenEmpty
boolean

When true, hides the content when there are no items matching the filter.

position
'inline' | 'popper'

The positioning mode to use,
inline is the default and you can control the position using CSS.
popper positions content in the same way as our other primitives, for example Popover or DropdownMenu.

positionStrategy
'fixed' | 'absolute'

The type of CSS position property to use.

prioritizePosition
boolean

Force content to be position within the viewport.

Might overlap the reference element, which may not be desired.

reference
ReferenceElement

The custom element or virtual element that will be set as the reference to position the floating element.

If provided, it will replace the default anchor element.

side
'top' | 'right' | 'bottom' | 'left'

The preferred side of the trigger to render against when open. Will be reversed when collisions occur and avoidCollisions is enabled.

sideFlip
boolean

Flip to the opposite side when colliding with boundary.

sideOffset
number

The distance in pixels from the trigger.

sticky
'partial' | 'always'

The sticky behavior on the align axis. partial will keep the content in the boundary as long as the trigger is at least partially in the boundary whilst "always" will keep the content in the boundary regardless.

updatePositionStrategy
'always' | 'optimized'

Strategy to update the position of the floating element on every animation frame.

EmitPayload
escapeKeyDown
[event: KeyboardEvent]

Event handler called when the escape key is down. Can be prevented.

focusOutside
[event: FocusOutsideEvent]

Event handler called when the focus moves outside of the DismissableLayer. Can be prevented.

interactOutside
[event: PointerDownOutsideEvent | FocusOutsideEvent]

Event handler called when an interaction happens outside the DismissableLayer. Specifically, when a pointerdown event happens outside or focus moves outside of it. Can be prevented.

pointerDownOutside
[event: PointerDownOutsideEvent]

Event handler called when a pointerdown event happens outside of the DismissableLayer. Can be prevented.

Data AttributeValue
[data-state]"open" | "closed"
[data-side]"left" | "right" | "bottom" | "top"
[data-align]"start" | "end" | "center"
[data-empty]Present when there are no items matching the filter
CSS VariableDescription
--reka-combobox-content-transform-origin
The transform-origin computed from the content and arrow positions/offsets. Only present when position="popper".
--reka-combobox-content-available-width
The remaining width between the trigger and the boundary edge. Only present when position="popper".
--reka-combobox-content-available-height
The remaining height between the trigger and the boundary edge. Only present when position="popper".
--reka-combobox-trigger-width
The width of the trigger. Only present when position="popper".
--reka-combobox-trigger-height
The height of the trigger. Only present when position="popper".

Viewport

The scrolling viewport that contains all of the items.

PropDefaultType
as
'div'
AsTag | Component

The element or component this component should render as. Can be overwritten by asChild.

asChild
boolean

Change the default rendered element for the one passed as a child, merging their props and behavior.

Read our Composition guide for more details.

nonce
string

Will add nonce attribute to the style tag which can be used by Content Security Policy.
If omitted, inherits globally from ConfigProvider.

Item

The component that contains the autocomplete items. When selected, the item's string value fills the input.

PropDefaultType
as
'div'
AsTag | Component

The element or component this component should render as. Can be overwritten by asChild.

asChild
boolean

Change the default rendered element for the one passed as a child, merging their props and behavior.

Read our Composition guide for more details.

disabled
boolean

When true, prevents the user from interacting with the item.

textValue
string

A string representation of the item contents.

If the children are not plain text, then the textValue prop must also be set to a plain text representation, which will be used for autocomplete in the ComboBox.

value*
AcceptableValue

The value given as data when submitted with a name.

EmitPayload
select
[event: SelectEvent<AcceptableValue>]

Event handler called when the selecting item.
It can be prevented by calling event.preventDefault.

Data AttributeValue
[data-state]"checked" | "unchecked"
[data-highlighted]Present when highlighted
[data-disabled]Present when disabled

Group

Used to group multiple items. Use in conjunction with AutocompleteLabel to ensure good accessibility via automatic labelling.

PropDefaultType
as
'div'
AsTag | Component

The element or component this component should render as. Can be overwritten by asChild.

asChild
boolean

Change the default rendered element for the one passed as a child, merging their props and behavior.

Read our Composition guide for more details.

Label

Used to render the label of a group. It won't be focusable using arrow keys.

PropDefaultType
as
'div'
AsTag | Component

The element or component this component should render as. Can be overwritten by asChild.

asChild
boolean

Change the default rendered element for the one passed as a child, merging their props and behavior.

Read our Composition guide for more details.

for
string

Separator

Used to visually separate items in the Autocomplete.

PropDefaultType
as
'div'
AsTag | Component

The element or component this component should render as. Can be overwritten by asChild.

asChild
boolean

Change the default rendered element for the one passed as a child, merging their props and behavior.

Read our Composition guide for more details.

Arrow

An optional arrow element to render alongside the content. This can be used to help visually link the trigger with the AutocompleteContent. Must be rendered inside AutocompleteContent. Only available when position is set to popper.

PropDefaultType
as
'svg'
AsTag | Component

The element or component this component should render as. Can be overwritten by asChild.

asChild
boolean

Change the default rendered element for the one passed as a child, merging their props and behavior.

Read our Composition guide for more details.

height
5
number

The height of the arrow in pixels.

rounded
boolean

When true, render the rounded version of arrow. Do not work with as/asChild

width
10
number

The width of the arrow in pixels.

Virtualizer

Virtual container to achieve list virtualization.

See the virtualization guide for more general info on virtualization.

PropDefaultType
estimateSize
number | ((index: number) => number)

Estimated size (in px) of each item

options*
AcceptableValue[]

List of items

overscan
number

Number of items rendered outside the visible area

textContent
((option: AcceptableValue) => string)

Text content for each item to achieve type-ahead feature

Slots (default)Payload
option
null | string | number | bigint | Record<string, any>
virtualizer
Virtualizer<HTMLElement, Element>
virtualItem
VirtualItem

Examples

Basic usage

The modelValue is a string that reflects whatever the user types. Selecting an item fills the input with that item's text.

vue
<script setup lang="ts">
import { AutocompleteContent, AutocompleteInput, AutocompleteItem, AutocompletePortal, AutocompleteRoot } from 'reka-ui'
import { ref } from 'vue'

const searchText = ref('')
const fruits = ['Apple', 'Banana', 'Orange', 'Grapes', 'Pineapple']
</script>

<template>
  <AutocompleteRoot v-model="searchText">
    <AutocompleteInput placeholder="Type a fruit..." />
    <AutocompletePortal>
      <AutocompleteContent>
        <AutocompleteItem
          v-for="fruit in fruits"
          :key="fruit"
          :value="fruit"
        >
          {{ fruit }}
        </AutocompleteItem>
      </AutocompleteContent>
    </AutocompletePortal>
  </AutocompleteRoot>
</template>

Hide menu when empty

Use the hideWhenEmpty prop on AutocompleteContent to hide the menu when no items match the filter.

vue
<template>
  <AutocompleteRoot v-model="searchText">
    <AutocompleteInput placeholder="Type a fruit..." />
    <AutocompletePortal>
      <AutocompleteContent hide-when-empty>
        <AutocompleteItem
          v-for="fruit in fruits"
          :key="fruit"
          :value="fruit"
        >
          {{ fruit }}
        </AutocompleteItem>
      </AutocompleteContent>
    </AutocompletePortal>
  </AutocompleteRoot>
</template>

With form submission

The Autocomplete value is submitted as a regular text field in forms.

vue
<script setup lang="ts">
import { AutocompleteContent, AutocompleteInput, AutocompleteItem, AutocompletePortal, AutocompleteRoot } from 'reka-ui'
import { ref } from 'vue'

const query = ref('')
const cities = ['New York', 'Los Angeles', 'Chicago', 'Houston', 'Phoenix']
</script>

<template>
  <form>
    <AutocompleteRoot v-model="query" name="city">
      <AutocompleteInput placeholder="Enter a city..." />
      <AutocompletePortal>
        <AutocompleteContent>
          <AutocompleteItem
            v-for="city in cities"
            :key="city"
            :value="city"
          >
            {{ city }}
          </AutocompleteItem>
        </AutocompleteContent>
      </AutocompletePortal>
    </AutocompleteRoot>
  </form>
</template>

Accessibility

Adheres to the Combobox WAI-ARIA design pattern.

Keyboard Interactions

KeyDescription
Enter
When focus is on AutocompleteItem, selects the focused item and fills the input with its value.
ArrowDown
When focus is on AutocompleteInput, opens the autocomplete content.
When focus is on an item, moves focus to the next item.
ArrowUp
When focus is on AutocompleteInput, opens the autocomplete content.
When focus is on an item, moves focus to the previous item.
Esc
Closes the autocomplete content and returns focus to AutocompleteInput.