De ce autocomplete-ul generic nu e suficient
Librăriile de autocomplete de adrese proiectate pentru piețe vestice pornesc de la niște premise care nu se potrivesc cu România:
- Presupun că adresele au formatul "stradă, număr, oraș, cod poștal" în această ordine - Nu cunosc nomenclatura românească (Str., Bd., Calea, Șos., Aleea, B-dul) - Nu gestionează diacriticele românești — "ș", "ț", "ă", "â", "î" - Nu știu că "Sector 3" este o subdiviziune a Bucureștiului, nu un județ
Rezultatul: sugestii irelevante, frustrare la checkout și livrări la adrese incomplete.
Endpoint-ul de autocomplete
GET /v1/addresses/autocomplete?q={query}&limit={n} acceptă un query parțial și returnează până la n sugestii (implicit 10, maxim 25):
curl "https://api.posty.ro/v1/addresses/autocomplete?q=mihai+vite&limit=5" \
-H "Authorization: Bearer psk_live_xxx"
{
"suggestions": [
{
"display": "Strada Mihai Viteazu, Cluj-Napoca, Cluj, 400151",
"components": {
"street": "Strada Mihai Viteazu",
"locality": "Cluj-Napoca",
"county": "Cluj",
"county_code": "CJ",
"postal_code": "400151"
},
"highlight": "Strada <em>Mihai</em> <em>Vite</em>azu, Cluj-Napoca, Cluj, 400151",
"score": 0.98,
"place_id": "psl_Y2x1ai1zdHJlZXQ"
}
],
"query": { "q": "mihai vite", "normalized": "mihai vite" }
}
Latența țintă este sub 150 ms la percentila 95, potrivită pentru un dropdown live.
Pattern de implementare
1. Debounce, nu throttle
Userul tastează rapid. Un debounce de 200–300 ms reduce numărul de cereri fără a degrada experiența percepută:
import { ref, watch } from 'vue'
const query = ref('') const suggestions = ref([]) let timer: ReturnType<typeof setTimeout>
watch(query, (val) => { clearTimeout(timer) if (val.length < 3) { suggestions.value = []; return } timer = setTimeout(async () => { const res = await fetch( https://api.posty.ro/v1/addresses/autocomplete?q=${encodeURIComponent(val)}, { headers: { Authorization: Bearer ${apiKey} } } ) const data = await res.json() suggestions.value = data.suggestions }, 250) })
2. Începe de la 3 caractere
Sub 3 caractere, sugestiile sunt prea largi pentru a fi utile și consumă quota inutil. Poți afișa un hint "continuă să tastezi…" pentru UX.
3. Oferă o ieșire manuală
Autocomplete-ul nu va acoperi 100% din adrese — există construcții noi, adrese temporare sau greșeli în sursele de date. Asigură-te că userul poate ignora sugestiile și continua cu ce a scris.
4. Pre-completează câmpurile la selecție
Când userul selectează o sugestie, populează automat câmpurile de județ, localitate și cod poștal din components din răspuns, și afișează display în input. Elimini astfel o sursă majoră de greșeli.
function selectSuggestion(s) {
form.street = s.components.street
form.locality = s.components.locality
form.county = s.components.county
form.postalCode = s.components.postal_code
}
5. Validează la submit
Autocomplete reduce erorile, dar nu le elimină. La submit, trimite adresa la POST /v1/addresses/verify pentru a prinde modificările manuale pe care userul le-a făcut după selecție.
Diacritice și toleranță la greșeli
API-ul normalizează intern atât query-ul cât și datele. "mihai vitezu" (fără diacritice), "MIHAI VITEAZU" (majuscule) și "Mihai Viteazu" returnează aceleași sugestii. Nu trebuie să preprocesezi input-ul clientului.
Accesibilitate
Un dropdown de autocomplete trebuie să respecte pattern-ul combobox din WAI-ARIA: - role="combobox" pe input, cu aria-expanded și aria-controls corecte - role="listbox" pe container și role="option" pe fiecare sugestie - Navigare cu tastele săgeată, Enter pentru selecție, Escape pentru închidere
Biblioteca NuxtUI USelectMenu și UCommandPalette implementează acest pattern corect — le poți folosi ca bază.