Skip to content

Autocomplete

Autocomplete input with dropdown suggestions and keyboard navigation. Supports custom option rendering, filtering, and various data formats.

Shared option API

Accepts the shared option formats — primitive arrays, object arrays with extractors, key-value objects and groups. See Option Extractors.

Import

typescript
import { Autocomplete } from 'vuiii'

Basic Usage

vue
<Autocomplete v-model="search" :options="['Apple', 'Banana', 'Blueberry', 'Cherry']" />

The v-model is the text in the field, not the picked option — take that from the select event. Arrow keys move through the list, Enter picks the highlighted option, and Escape closes it.

Props

PropTypeDefaultDescription
modelValuestring''Input text value (v-model)
optionsT[] | Record<string, any>-Options to display in the dropdown
optionLabelstring | ((item) => any)-Key or function to extract the display label
optionValuestring | ((item) => any)-Key or function to extract the option value
optionDisabledstring | ((item) => any)-Key or function to mark an option as disabled
optionDescriptionstring | ((item) => any)-Key or function to extract description text
optionIconstring | ((item) => any)-Key or function to extract the icon name
groupLabelstring | ((item) => any)-Key or function to extract a group's label
groupOptionsstring | ((item) => any)-Key or function to extract a group's options
placeholderstring-Input placeholder text
disabledbooleanfalseDisables the input
size'small' | 'normal' | 'large''normal'Input size
invalidbooleanfalseShows the invalid/error styling
pillbooleanfalseRounded pill shape
prefixIconstring-Icon name to show before the input
suffixIconstring-Icon name to show after the input
filter(option: Option, query: string) => boolean-Custom filter function
dropdownPlacement'left' | 'right' | 'center'-Dropdown alignment relative to the input
inputClassany-Class(es) applied to the native input element

Slots

SlotDescription
prefixContent before the input (replaces prefixIcon)
suffixContent after the input (replaces suffixIcon)
optionCustom option rendering. Props: { option, index, isHighlighted }
optionGroupCustom group heading. Props: { label }

Events

EventPayloadDescription
selectOption<T>When an option is selected
prefix-icon-click-When the prefix icon is clicked
suffix-icon-click-When the suffix icon is clicked

Object Options

option-description renders a second line under each suggestion. The select event carries the whole normalized option, with your original item in data.

vue
<Autocomplete
  v-model="search"
  :options="users"
  option-label="name"
  option-value="id"
  option-description="email"
  @select="(option) => (selectedUser = option.data)"
/>

Custom Filter

By default an option matches when the query appears anywhere in its label or description. Pass filter to decide yourself — here, only a prefix match counts.

vue
<script setup>
const startsWithFilter = (option, query) => option.label.toLowerCase().startsWith(query.toLowerCase())
</script>

<template>
  <Autocomplete v-model="search" :options="options" :filter="startsWithFilter" />
</template>

Returning true unconditionally turns filtering off entirely — useful when the options already come from a server that did the searching.

Custom Option Rendering

vue
<Autocomplete v-model="search" :options="users" option-label="name">
  <template #option="{ option, isHighlighted }">
    <div :class="{ highlighted: isHighlighted }">
      <strong>{{ option.label }}</strong>
      <small>{{ option.description }}</small>
    </div>
  </template>
</Autocomplete>

Grouped Options

Pass group-label and group-options to render the options under a heading per group. Filtering still runs across every group, and a group whose options are all filtered out drops its heading with them. Keyboard navigation steps over the options only — headings are never focusable.

vue
<script setup>
const options = [
  { category: 'Fruits', items: [{ id: 1, name: 'Apple' }, { id: 2, name: 'Banana' }] },
  { category: 'Vegetables', items: [{ id: 3, name: 'Carrot' }] },
]
</script>

<template>
  <Autocomplete
    v-model="search"
    :options="options"
    group-label="category"
    group-options="items"
    option-value="id"
    option-label="name"
  />
</template>

Use the optionGroup slot to render the heading yourself:

vue
<Autocomplete v-model="search" :options="options" group-label="category" group-options="items">
  <template #optionGroup="{ label }">
    <Icon name="folder" /> {{ label }}
  </template>
</Autocomplete>

Accessibility

Headings are rendered as presentational entries inside the listbox, so they are shown but not announced — screen reader users hear the options without their group. Grouping is a visual aid here; do not rely on it to convey meaning that the option labels do not already carry.

Storybook

For interactive examples with all variants, see Autocomplete in Storybook.

Released under the MIT License.