Vue Autocomplete Component

Autocomplete

CoreUI PRO
This component is part of CoreUI PRO – a powerful UI library with over 250 components and 25+ templates, designed to help you build modern, responsive apps faster. Fully compatible with Angular, Bootstrap, React.js, and Vue.js.

Build powerful Vue Autocomplete components with dynamic search, dropdown suggestions, and external data integration. The ultimate Vue.js Autocomplete solution for modern web applications.

Available in Other JavaScript Frameworks

CoreUI Vue Autocomplete Component is also available for Angular, Bootstrap, and React. Explore framework-specific implementations below:

Overview

The Vue Autocomplete Component is a powerful, feature-rich autocomplete solution that enhances form usability by providing intelligent suggestions as users type. Whether you’re building a Vue.js autocomplete with static array data, fetching data from APIs, or implementing complex search logic, this autocomplete component delivers a smooth, accessible user experience with extensive customization options.

Key features of this Vue Autocomplete include:

  • Dynamic dropdown suggestions with real-time filtering
  • External data integration with API support
  • Customizable templates and custom styles
  • Advanced search capabilities
  • Performance optimization with virtual scrolling
  • Accessibility-first design

Basic example

A straightforward demonstration of how to implement a basic autocomplete input field, highlighting essential attributes and configurations.

vue
<template>
  <CAutocomplete
    cleaner
    highlightOptionsOnSearch
    indicator
    label="Framework"
    :options="['Angular', 'Bootstrap', 'Next.js', 'React.js', 'Vue.js']"
    placeholder="Search technologies..."
    search="global"
    searchNoResultsLabel="No results found"
    showHints
    text="Start typing to search option or provide value"
    value="Bootstrap"
  />
</template>

<script setup>
import { CAutocomplete } from '@coreui/vue-pro'
</script>

You can also use objects with value and label properties for more structured data:

vue
<template>
  <CAutocomplete
    cleaner
    highlightOptionsOnSearch
    indicator
    label="Framework"
    :options="options"
    placeholder="Search technologies..."
    search="global"
    searchNoResultsLabel="No results found"
    showHints
    text="Start typing to search option or provide value"
    :value="1"
  />
</template>

<script setup>
import { CAutocomplete } from '@coreui/vue-pro'

const options = [
  { label: 'Angular', value: 1 },
  { label: 'Bootstrap', value: 2 },
  { label: 'Next.js', value: 3 },
  { label: 'React.js', value: 4 },
  { label: 'Vue.js', value: 5 },
]
</script>

For a minimal implementation without additional features:

<template>
  <CAutocomplete
    label="Framework"
    :options="['Angular', 'Bootstrap', 'Next.js', 'React.js', 'Vue.js']"
    placeholder="Search technologies..."
    text="Start typing to search option or provide value"
  />
</template>

Component v-model support

The Vue Autocomplete component supports Vue 3’s v-model directive for two-way data binding. When using string arrays, v-model binds to the string value. When using object arrays, v-model binds to the value property of the selected option.

vue
<template>
  <CRow>
    <CCol md="6">
      <CAutocomplete
        v-model="selectedFramework"
        label="Framework (v-model)"
        :options="frameworks"
        placeholder="Select framework..."
        text="Using v-model with string array"
      />
      <p class="mt-2">Selected: {{ selectedFramework || 'None' }}</p>
    </CCol>
    <CCol md="6">
      <CAutocomplete
        v-model="selectedCountry"
        label="Country (v-model)"
        :options="countries"
        placeholder="Select country..."
        text="Using v-model with object array"
      />
      <p class="mt-2">Selected value: {{ selectedCountry || 'None' }}</p>
    </CCol>
  </CRow>
</template>

<script setup>
import { ref } from 'vue'
import { CRow, CCol } from '@coreui/vue'
import { CAutocomplete } from '@coreui/vue-pro'

const selectedFramework = ref('Vue.js')
const selectedCountry = ref('us')

const frameworks = ['Angular', 'Bootstrap', 'Next.js', 'React.js', 'Vue.js']

const countries = [
  { value: 'pl', label: 'Poland' },
  { value: 'de', label: 'Germany' },
  { value: 'us', label: 'United States' },
  { value: 'es', label: 'Spain' },
  { value: 'gb', label: 'United Kingdom' },
]
</script>

Search functionality

Configure the search behavior to match your application’s needs. The search prop determines how the component handles user input and filtering.

By default, search operates only when the input field is focused and filters options internally:

vue
<template>
  <CAutocomplete
    :options="['Angular', 'Bootstrap', 'Next.js', 'React.js', 'Vue.js']"
    placeholder="Search technologies..."
  />
</template>

<script setup>
import { CAutocomplete } from '@coreui/vue-pro'
</script>

Enable global search functionality that allows users to start typing from anywhere within the component to begin searching:

vue
<template>
  <CAutocomplete
    :options="['Angular', 'Bootstrap', 'Next.js', 'React.js', 'Vue.js']"
    placeholder="Search technologies..."
    search="global"
    text="Click on component and start typing"
  />
</template>

<script setup>
import { CAutocomplete } from '@coreui/vue-pro'
</script>

When external search is enabled (search="external"), the component delegates search operations to your custom logic or external API. This is perfect for server-side filtering, complex search algorithms, or third-party search services:

<template>
  <CAutocomplete 
    :options="filteredOptions" 
    search="external" 
    @input="handleSearch" 
  />
</template>

You can combine external search with global keyboard navigation:

<template>
  <CAutocomplete 
    :options="filteredOptions" 
    :search="{ external: true, global: true }" 
    @input="handleSearch" 
  />
</template>

See the External Data section for a complete working example.

Restricted selection

Limit users to only select from the provided options by enabling allow-only-defined-options. This prevents custom value entry:

vue
<template>
  <CAutocomplete
    allowOnlyDefinedOptions
    label="Framework"
    :options="['Angular', 'Bootstrap', 'Next.js', 'React.js', 'Vue.js']"
    placeholder="Only predefined options allowed..."
    text="Try typing a custom value - it won't be selectable"
  />
</template>

<script setup>
import { CAutocomplete } from '@coreui/vue-pro'
</script>

Blur behavior

The autocomplete component includes intelligent blur handling that improves user experience by automatically selecting matching options when the user leaves the input field.

Auto-selection on exact match

When a user types a value that exactly matches one option (case-insensitive) and then blurs the input field, the component automatically selects that option:

Example scenario:

  • Available options: “Apple”, “Banana”, “Cherry”
  • User types “apple” (lowercase) and clicks outside the field
  • Result: “Apple” is automatically selected
vue
<template>
  <CAutocomplete
    label="Fruit"
    :options="['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry']"
    placeholder="Type apple (lowercase) and click outside..."
    text="The component will auto-select Apple when you blur with an exact match"
  />
</template>

<script setup>
import { CAutocomplete } from '@coreui/vue-pro'
</script>

Strict mode behavior

When allow-only-defined-options is enabled, the blur behavior enforces strict validation:

  • Exact match found: The matching option is automatically selected
  • No exact match: The input field is cleared to prevent invalid values
vue
<template>
  <CAutocomplete
    allowOnlyDefinedOptions
    label="Fruit"
    :options="['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry']"
    placeholder="Try typing orange and blur..."
    text="In strict mode, invalid values are cleared on blur"
  />
</template>

<script setup>
import { CAutocomplete } from '@coreui/vue-pro'
</script>

Non-strict mode behavior (default)

Without allow-only-defined-options, the component allows custom values:

  • Exact match found: The matching option is automatically selected
  • No exact match: The custom value is accepted and emitted via the change event
  • Partial match: No auto-selection occurs; the input value remains

This is useful when users should be able to enter values not in the predefined list:

vue
<template>
  <CAutocomplete
    v-model="selectedValue"
    label="Fruit"
    :options="['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry']"
    placeholder="Type any value and blur..."
    text="Custom values are accepted when allowOnlyDefinedOptions is false"
    @change="handleChange"
  />
  <div v-if="customValue" class="mt-3">
    <strong>Custom value entered:</strong> {{ customValue }}
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { CAutocomplete } from '@coreui/vue-pro'

const selectedValue = ref(null)
const customValue = ref('')

const handleChange = (value) => {
  if (typeof value === 'string') {
    customValue.value = value
  }
}
</script>

User experience enhancements

Enable intelligent hints and auto-completion features to improve user experience.

Show hints

Display intelligent completion hints that preview the first matching option as users type:

vue
<template>
  <CAutocomplete
    label="Framework"
    :options="['Angular', 'Bootstrap', 'Next.js', 'React.js', 'Vue.js']"
    placeholder="Type to see hints..."
    showHints
    text="Start typing to see preview hints"
  />
</template>

<script setup>
import { CAutocomplete } from '@coreui/vue-pro'
</script>

Highlight matching text

Enhance search visibility by highlighting matching portions of option labels when users hover over suggestions:

vue
<template>
  <CAutocomplete
    highlightOptionsOnSearch
    label="Framework"
    :options="['Angular', 'Bootstrap', 'Next.js', 'React.js', 'Vue.js']"
    placeholder="Type to see highlighted matches..."
    text="Search terms will be highlighted in the dropdown options"
  />
</template>

<script setup>
import { CAutocomplete } from '@coreui/vue-pro'
</script>

Validation states

Apply validation styling to indicate input validity.

vue
<template>
  <CRow>
    <CCol :md="6">
      <CAutocomplete
        invalid
        feedbackInvalid="Please select a valid option"
        label="Invalid state"
        :options="['Angular', 'Bootstrap', 'Next.js', 'React.js', 'Vue.js']"
        placeholder="Invalid autocomplete..."
      />
    </CCol>
    <CCol :md="6">
      <CAutocomplete
        valid
        feedbackValid="Looks good!"
        label="Valid state"
        :options="['Angular', 'Bootstrap', 'Next.js', 'React.js', 'Vue.js']"
        placeholder="Valid autocomplete..."
        value="Vue.js"
      />
    </CCol>
  </CRow>
</template>

<script setup>
import { CRow, CCol } from '@coreui/vue'
import { CAutocomplete } from '@coreui/vue-pro'
</script>

Disabled state

Disable the component to prevent user interaction:

vue
<template>
  <CAutocomplete
    disabled
    label="Framework"
    :options="['Angular', 'Bootstrap', 'Next.js', 'React.js', 'Vue.js']"
    placeholder="Disabled autocomplete..."
    value="Vue.js"
  />
</template>

<script setup>
import { CAutocomplete } from '@coreui/vue-pro'
</script>

Sizing

Choose from different sizes to match your design system and form layout:

vue
<template>
  <CAutocomplete
    :options="['Angular', 'Bootstrap', 'Next.js', 'React.js', 'Vue.js']"
    placeholder="Small size..."
    size="sm"
  />
  <CAutocomplete
    :options="['Angular', 'Bootstrap', 'Next.js', 'React.js', 'Vue.js']"
    placeholder="Default size..."
  />
  <CAutocomplete
    :options="['Angular', 'Bootstrap', 'Next.js', 'React.js', 'Vue.js']"
    placeholder="Large size..."
    size="lg"
  />
</template>

<script setup>
import { CAutocomplete } from '@coreui/vue-pro'
</script>

Cleaner functionality

Enable a cleaner button to quickly clear the input element:

vue
<template>
  <CAutocomplete
    cleaner
    :options="['Angular', 'Bootstrap', 'Next.js', 'React.js', 'Vue.js']"
    placeholder="With cleaner button..."
  />
</template>

<script setup>
import { CAutocomplete } from '@coreui/vue-pro'
</script>

Custom templates

The CoreUI Vue Autocomplete Component provides the flexibility to personalize options and group labels by utilizing custom templates. You can easily customize the options using scoped slots:

  • #options="{ option }" - For customizing individual option rendering
  • #options-groups="{ option }" - For customizing option group headers
vue
<template>
  <CRow>
    <CCol md="6">
      <CAutocomplete label="Country" :options="countries" placeholder="Select country" showHints>
        <template #options="{ option }">
          <div class="d-flex">
            <CIcon :icon="flags[option.value]" size="xl" class="me-3" />
            {{ option.label }}
          </div>
        </template>
      </CAutocomplete>
    </CCol>
    <CCol md="6">
      <CAutocomplete label="City" :options="cities" placeholder="Select city" showHints>
        <template #options-groups="{ option }">
          <div class="d-flex align-items-center">
            <CIcon :icon="flags[option.code]" size="xl" class="me-3" />
            {{ option.label }}
          </div>
        </template>
      </CAutocomplete>
    </CCol>
  </CRow>
</template>

<script setup>
import { CRow, CCol } from '@coreui/vue'
import { CAutocomplete } from '@coreui/vue-pro'
import CIcon from '@coreui/icons-vue'
import { cifPl, cifDe, cifUs, cifEs, cifGb } from '@coreui/icons'

const flags = {
  de: cifDe,
  es: cifEs,
  gb: cifGb,
  pl: cifPl,
  us: cifUs,
}

const countries = [
  { value: 'pl', label: 'Poland' },
  { value: 'de', label: 'Germany' },
  { value: 'us', label: 'United States' },
  { value: 'es', label: 'Spain' },
  { value: 'gb', label: 'United Kingdom' },
]

const cities = [
  {
    label: 'United States',
    code: 'us',
    options: [
      { value: 'au', label: 'Austin' },
      { value: 'ch', label: 'Chicago' },
      { value: 'la', label: 'Los Angeles' },
      { value: 'ny', label: 'New York' },
      { value: 'sa', label: 'San Jose' },
    ],
  },
  {
    label: 'United Kingdom',
    code: 'gb',
    options: [
      { value: 'li', label: 'Liverpool' },
      { value: 'lo', label: 'London' },
      { value: 'ma', label: 'Manchester' },
    ],
  },
]
</script>

Basic slot usage

<template>
  <CAutocomplete :options="options" placeholder="Search...">
    <template #options="{ option }">
      <div class="custom-option">
        <strong>{{ option.label }}</strong>
        <small class="text-muted">{{ option.description }}</small>
      </div>
    </template>
    
    <template #options-groups="{ option }">
      <div class="custom-group">
        <strong>{{ option.label }}</strong>
      </div>
    </template>
  </CAutocomplete>
</template>

External Data

One of the most powerful features of the Vue Autocomplete component is its ability to work with external data sources, such as REST APIs, GraphQL endpoints, or server-side search services. This is essential when dealing with large datasets that shouldn’t be loaded entirely into the client.

Implementation example

Here’s how to implement external data loading with proper debouncing to optimize API calls:

vue
<template>
  <CAutocomplete
    cleaner
    highlightOptionsOnSearch
    indicator
    label="Users"
    :loading="loading"
    :options="users"
    placeholder="Search users..."
    :search="{ external: true, global: true }"
    showHints
    text="Please select your user."
    virtualScroller
    @input="debouncedGetUsers"
    @show="getUsers"
  />
</template>

<script setup>
import { ref } from 'vue'
import { CAutocomplete, useDebouncedCallback } from '@coreui/vue-pro'

const loading = ref(false)
const users = ref([])

const getUsers = async (name = '') => {
  loading.value = true
  try {
    const response = await fetch(`https://apitest.coreui.io/demos/users?first_name=${name}`)
    const result = await response.json()

    users.value = result.records.map((record) => ({
      value: record.id,
      label: record.first_name,
    }))
  } catch (error) {
    console.error('Error fetching users:', error)
    users.value = [] // Optionally handle an error state
  } finally {
    loading.value = false
  }
}

// Using CoreUI's built-in debounced callback composable
const debouncedGetUsers = useDebouncedCallback((value) => {
  getUsers(value)
}, 300)
</script>

Key features for external data

  • Debounced search: Prevents excessive API calls during rapid typing
  • search="external": Disables internal filtering to rely on server-side search
  • loading prop: Shows loading indicators during API requests
  • virtual-scroller: Efficiently renders large result sets
  • search-no-results-label: Provides user feedback when no results are found

Debouncing implementation

You can implement debouncing using a simple timeout mechanism as shown in the example above, or use CoreUI’s built-in useDebouncedCallback composable:

Alternatively, you can use @vueuse/core’s useDebouncedRef:

Performance optimization

For large datasets, the Vue Autocomplete component includes several performance optimizations:

  • Virtual scrolling: Use virtual-scroller to render only visible options
  • Debounced search: Implement search debouncing to reduce API calls
  • External filtering: Delegate filtering to the server with search="external"
  • Lazy loading: Load data only when needed

Events

The Vue Autocomplete component emits the following events:

  • @change: Fired when the selected option changes. Receives (option: Option | null)
  • @input: Fired when the search input value changes. Receives (value: string)
  • @show: Fired when the dropdown opens
  • @hide: Fired when the dropdown closes
  • @update:modelValue: Fired when the model value changes (for v-model support). Receives (value: number | string | null)
<template>
  <CAutocomplete
    v-model="selectedValue"
    :options="options"
    @change="handleChange"
    @input="handleInput"
    @show="handleShow"
    @hide="handleHide"
  />
</template>