Address autocomplete in Vue with the Locio package

About 6 minutes. Updated 18 September 2026.

Install the published Vue client and get an accessible address autocomplete as a single component, with the debouncing and request cancellation already done, v-model support and every class name still yours.

There is a guide that builds this by hand with a ref and a watcher. This one installs @locio-au/vue instead, which is the same component with the debouncing, the aborts and the keyboard handling already written.

01Install it

sh
npm install @locio-au/vue

Vue 3 as a peer dependency, and nothing else. No styles and no state library come with it.

02Drop the component in

It is one single file component using script setup, and it emits the picked address so the parent can store the address id. Results come from /v1/addresses.

src/CheckoutForm.vuevue
<!-- src/CheckoutForm.vue -->
<script setup lang="ts">
import { ref } from "vue";
import { AddressAutocomplete, addressId, type Address } from "@locio-au/vue";

const address = ref<Address | null>(null);
</script>

<template>
  <form>
    <AddressAutocomplete
      :public-key="key"
      label="Delivery address"
      @select="address = $event"
    />

    <input v-if="address" type="hidden" name="address_id" :value="addressId(address)" />
  </form>
</template>

Store addressId(address). It is the address's id in its country's register, which in Australia is the G-NAF Address Detail PID, sent under address_detail_pid as well. It is stable across releases for an address that has not changed, where the formatted line is not, so it is the thing to key your own records on rather than the text. addressId rather than address.id: the field is optional on the package's type, because a service one release behind sends only the G-NAF names, and the helper reads whichever arrived.

03Make it look like your form

Pass your own classes for each slot, and set styled to false to drop the package's inline styles so there is nothing to override.

src/CheckoutForm.vuevue
<AddressAutocomplete
  :public-key="key"
  :styled="false"
  :class-names="{
    root: 'field',
    label: 'field-label',
    input: 'field-input',
    list: 'field-list',
    option: 'field-option',
    status: 'field-status',
  }"
  @select="address = $event"
/>

04Or take the composable

The component wraps a composable, and you can use it directly when you want your own markup. It returns refs, so it drops into a template the way anything else does.

src/Search.vuevue
<script setup lang="ts">
import { addressId, useAddressAutocomplete } from "@locio-au/vue";

// note and countryCode are what the service said about the country it
// searched: somebody typing from a country with no address data gets no
// results and a sentence saying so, which is the one to show them.
const { term, results, status, note, countryCode } = useAddressAutocomplete({
  publicKey: import.meta.env.VITE_LOCIO_KEY,
  debounceMs: 300,
  minLength: 3,
});
</script>

<template>
  <input v-model="term" />
  <p v-if="status === 'searching'">Searching</p>
  <p v-if="note">{{ note }}</p>
  <ul>
    <li v-for="a in results" :key="addressId(a)">{{ a.formatted }}</li>
  </ul>
  <p v-if="countryCode">Searched {{ countryCode }}</p>
</template>

What it costs

One unit per request, with the same 300 millisecond debounce and three character minimum as the other clients. A completed address is usually three or four requests, and refused requests are free.

The key

A public key, always, with your origins listed on it. The client refuses a secret key when it sees a browser rather than letting one reach your users. Create a key.

Related