Forms

AutoComplete

Campo di input con suggerimenti automatici caricati dinamicamente tramite l'evento complete. Supporta selezione singola e multipla (chips), dropdown button e forceSelection.

Import

import { AutoComplete } from '@pzeta/vue-components'

Esempio Base

<script setup lang="ts">
import { ref } from 'vue'

const selectedCountry = ref(null)
const suggestions = ref<string[]>([])

const allCountries = ['Italia', 'Francia', 'Germania', 'Spagna', 'Portogallo']

function search(event: { query: string }) {
  const query = event.query.toLowerCase()
  suggestions.value = allCountries.filter(c => c.toLowerCase().includes(query))
}
</script>

<template>
  <AutoComplete
    v-model="selectedCountry"
    :suggestions="suggestions"
    placeholder="Cerca un paese..."
    label="Paese"
    @complete="search"
  />
</template>

Come funziona l'evento complete

L'evento complete viene emesso ogni volta che l'utente digita nel campo (dopo il delay configurato e con almeno minLength caratteri). Il gestore deve popolare la prop :suggestions con i risultati filtrati. Il componente non filtra autonomamente — la logica di ricerca è completamente a carico del consumatore (locale o API remota).

function search(event: { originalEvent: Event; query: string }) {
  // Filtraggio locale
  suggestions.value = allItems.filter(item =>
    item.toLowerCase().includes(event.query.toLowerCase())
  )

  // Oppure chiamata API
  // suggestions.value = await api.search(event.query)
}

Props

PropTipoDefaultDescrizione
modelValueT | T[] | nullValore corrente (v-model)
suggestionsT[]nullArray di suggerimenti da visualizzare nel dropdown
optionLabelstring | ((item: T) => string)nullCampo da usare come label quando T è un oggetto
optionValuestring | ((item: T) => unknown)nullCampo per il valore quando T è un oggetto
optionDisabledstring | ((item: T) => boolean)nullCampo per disabilitare opzioni
optionGroupLabelstring | ((group: T) => string)nullLabel gruppo opzioni
optionGroupChildrenstring | ((group: T) => T[])nullChildren gruppo opzioni
dataKeystringnullCampo univoco per tracking
placeholderstringnullPlaceholder dell'input
multiplebooleanfalseAbilita selezione multipla (chips)
typeaheadbooleantrueAbilita typeahead in modalità multiple
dropdownbooleanfalseMostra pulsante dropdown per aprire il pannello
dropdownMode'blank' | 'current''blank'Modalità del dropdown button: blank=ricerca vuota, current=ricerca con testo corrente
minLengthnumber1Numero minimo di caratteri per attivare la ricerca
delaynumber300Delay in ms prima di emettere l'evento complete
completeOnFocusbooleanfalseEmette complete al focus (mostra tutti i suggerimenti)
forceSelectionbooleanfalseForza la selezione da lista (svuota input se non selezionato)
autoHighlightbooleantrueEvidenzia automaticamente il primo suggerimento
showClearbooleanfalseMostra pulsante per azzerare la selezione
labelstringnullLabel mostrata sopra il campo
helperTextstringnullTesto di aiuto sotto il campo
errorstringnullMessaggio di errore
invalidbooleanfalseStato di validazione invalido
disabledbooleanfalseDisabilita il componente
readonlybooleanfalseCampo in sola lettura
requiredbooleanfalseCampo obbligatorio
fluidbooleanfalseOccupa tutta la larghezza disponibile
size'small' | 'medium' | 'large''medium'Dimensione del componente
variant'outlined' | 'filled''outlined'Variante visiva
severitySeverity'primary'Colore tema
loadingbooleanfalseStato di caricamento
scrollHeightstring'200px'Altezza massima del dropdown
appendTo'body' | 'self''body'Target Teleport del dropdown
inputIdstringnullID dell'input per accessibilità
inputClassstringnullClasse CSS aggiuntiva per l'input
inputStylestring | Record<string, string | number>nullStile inline per l'input
namestringnullNome per i form nativi
ariaLabelstringnullAria label per screen reader
ariaLabelledbystringnullID dell'elemento label ARIA
selectOnFocusbooleanfalseSeleziona il testo all'input al focus
autofocusbooleanfalseFocus automatico al mount
virtualScrollerOptionsRecord<string, unknown>nullOpzioni per virtual scroller

Emits

EventoPayloadDescrizione
update:modelValueT | T[] | nullAggiornamento v-model
complete{ originalEvent: Event, query: string }Emesso quando l'utente digita — popolare suggestions in risposta
itemSelect{ originalEvent: Event, value: T }Selezione di un suggerimento
itemUnselect{ originalEvent: Event, value: T }Deselezione in modalità multipla
dropdownClick{ originalEvent: Event, query: string }Click sul pulsante dropdown
change{ originalEvent: Event, value: T | T[] | null }Cambio valore
clearEventSelezione azzerata
focusFocusEventIl componente riceve il focus
blurFocusEventIl componente perde il focus
keydownKeyboardEventPressione tasto
beforeShowPrima dell'apertura del dropdown
showDropdown aperto
beforeHidePrima della chiusura del dropdown
hideDropdown chiuso

Slot

SlotScopeDescrizione
option{ option: T, index: number }Template per ogni singola opzione
optiongroup{ option: T }Template per l'intestazione del gruppo
headerContenuto in cima al dropdown
footerContenuto in fondo al dropdown
emptyMessaggio quando non ci sono suggerimenti
chip{ value: T }Template per ogni chip in modalità multipla
dropdowniconIcona del dropdown button personalizzata
loadingiconIcona di caricamento personalizzata
cleariconIcona del pulsante clear personalizzata
removetokeniconIcona di rimozione chip personalizzata

Esempi

Selezione multipla (tags)

In modalità multipla il v-model è un array. I valori selezionati vengono mostrati come chips nell'input. Premendo Backspace con l'input vuoto rimuove l'ultimo chip:

<script setup lang="ts">
const selectedTags = ref<string[]>([])
const tags = ref<string[]>([])

const allTags = ['Vue.js', 'React', 'Angular', 'TypeScript', 'Node.js']

function search(event: { query: string }) {
  tags.value = allTags.filter(t =>
    t.toLowerCase().includes(event.query.toLowerCase()) &&
    !selectedTags.value.includes(t)
  )
}
</script>

<template>
  <AutoComplete
    v-model="selectedTags"
    :suggestions="tags"
    :multiple="true"
    placeholder="Aggiungi tag..."
    label="Linguaggi e Framework"
    @complete="search"
  />
</template>

Con oggetti tipizzati

<script setup lang="ts">
interface Country { code: string; name: string }

const selected = ref<Country | null>(null)
const suggestions = ref<Country[]>([])

const allCountries: Country[] = [
  { code: 'IT', name: 'Italia' },
  { code: 'FR', name: 'Francia' },
]

function search(event: { query: string }) {
  suggestions.value = allCountries.filter(c =>
    c.name.toLowerCase().includes(event.query.toLowerCase())
  )
}
</script>

<template>
  <AutoComplete
    v-model="selected"
    :suggestions="suggestions"
    option-label="name"
    data-key="code"
    @complete="search"
  />
</template>

Con dropdown button

<AutoComplete
  v-model="selected"
  :suggestions="suggestions"
  dropdown
  dropdown-mode="blank"
  @complete="search"
  @dropdown-click="loadAll"
/>

completeOnFocus — mostra tutto al focus

<AutoComplete
  v-model="selected"
  :suggestions="suggestions"
  :complete-on-focus="true"
  :min-length="0"
  @complete="search"
/>

forceSelection — obbliga selezione dalla lista

Se l'utente digita qualcosa e poi esce senza selezionare, il campo viene svuotato:

<AutoComplete
  v-model="selected"
  :suggestions="suggestions"
  :force-selection="true"
  @complete="search"
/>

Slot option personalizzato

<AutoComplete v-model="selected" :suggestions="countries" option-label="name" @complete="search">
  <template #option="{ option }">
    <div class="flex items-center gap-2">
      <img :src="`/flags/${option.code}.svg`" class="w-6 h-4" />
      <span>{{ option.name }}</span>
    </div>
  </template>
</AutoComplete>

Stati

<AutoComplete :suggestions="[]" label="Disabilitato" disabled @complete="() => {}" />
<AutoComplete :suggestions="[]" label="Caricamento" loading @complete="() => {}" />
<AutoComplete
  v-model="val"
  :suggestions="[]"
  label="Errore"
  error="Campo obbligatorio"
  invalid
  @complete="() => {}"
/>

Accessibilità

  • L'input è un elemento <input type="text"> nativo con autocomplete="off"
  • Supporto navigazione tastiera: ArrowDown/Up naviga i suggerimenti, Enter seleziona, Escape chiude, Tab chiude il pannello
  • In modalità multipla Backspace con input vuoto rimuove l'ultimo chip
  • aria-label e aria-labelledby propagati all'input nativo

TypeScript

import type { AutoCompleteProps, AutoCompleteEmits, AutoCompleteCompleteEvent } from '@pzeta/vue-components'

function onComplete(event: AutoCompleteCompleteEvent) {
  // event.query contiene il testo digitato
  suggestions.value = filter(event.query)
}