Component

Autocomplete

<dom-autocomplete>

A styled datalist-like text input: free text stays separate from selected suggestions.

Playground

Try every prop live

Autocomplete playground

Edit props in the inspector — type to filter suggestions and test the free-text path.

  • Ada Lovelace
  • Grace Hopper
  • Katherine Johnson
Playground.vuevue
<script setup>
import { reactive } from 'vue';
import { DomAutocomplete } from '@getdom/studio/vue';

const data = reactive({
	  "modelValue": "",
	  "id": "",
	  "name": "",
	  "label": "",
	  "description": "",
	  "placeholder": "Search people",
	  "required": false,
	  "disabled": false,
	  "readOnly": false,
	  "invalid": false,
	  "errors": {},
	  "visible": true,
	  "validators": [],
	  "validateOnBlur": true,
	  "chrome": "field",
	  "options": [
	    {
	      "value": "1",
	      "label": "Ada Lovelace",
	      "email": "ada@example.com"
	    },
	    {
	      "value": "2",
	      "label": "Grace Hopper",
	      "email": "grace@example.com"
	    },
	    {
	      "value": "3",
	      "label": "Katherine Johnson",
	      "email": "katherine@example.com"
	    }
	  ],
	  "placement": "bottom",
	  "floatingMode": "viewport",
	  "loading": false
	});
</script>

<template>
	<DomAutocomplete
		v-bind="data"
		@update:modelValue="data.modelValue = $event"
	/>
</template>

Demo

Search people

v-model is the typed text. @select receives the original option object when a suggestion is chosen.

  • Ada Lovelace
  • Grace Hopper
  • Katherine Johnson

Typed text:

Selected item:

SearchPeople.vuevue
<script setup>
import { DomAutocomplete } from '@getdom/studio/vue';
import { ref } from 'vue';

const text = ref('');
const selected = ref(null);
const people = [
	{ value: '1', label: 'Ada Lovelace', email: 'ada@example.com' },
	{ value: '2', label: 'Grace Hopper', email: 'grace@example.com' },
	{ value: '3', label: 'Katherine Johnson', email: 'katherine@example.com' },
];

function onSelect(event) {
	selected.value = event.item;
}
</script>

<template>
	<div class="flex w-full max-w-sm flex-col gap-2">
		<DomAutocomplete
			v-model="text"
			:options="people"
			placeholder="Search people"
			class="w-full"
			@select="onSelect"
		/>
		<p class="text-xs text-muted-fg">Typed text: <code class="text-fg">{{ text || '—' }}</code></p>
		<p class="text-xs text-muted-fg">Selected item: <code class="text-fg">{{ selected?.email || '—' }}</code></p>
	</div>
</template>

Demo

Server-loaded suggestions

@query lets the parent fetch suggestions and pass the current server results back through options.

Suggestions are fetched by the parent in response to @query.

Text value: Empty

ServerLoadedPeople.vuevue
<script setup>
import { ref } from 'vue';
import { DomAutocomplete } from '@getdom/studio/vue';
import { searchPeople } from '../../_shared/serverLookup.js';

const value = ref('');
const options = ref([]);
const loading = ref(false);
let requestId = 0;

async function queryPeople(query) {
	const currentRequest = ++requestId;
	if (!query.trim()) {
		options.value = [];
		loading.value = false;
		return;
	}

	loading.value = true;
	const results = await searchPeople(query);
	if (currentRequest !== requestId) return;
	options.value = results.map((person) => ({
		...person,
		value: person.label,
		description: person.email,
	}));
	loading.value = false;
}
</script>

<template>
	<div class="grid w-full max-w-md gap-3">
		<DomAutocomplete
			v-model="value"
			:options="options"
			:loading="loading"
			label="Search people"
			description="Suggestions are fetched by the parent in response to @query."
			placeholder="Type a name"
			class="w-full"
			@query="queryPeople"
		>
			<template #item="{ item }">
				<span class="block min-w-0">
					<span class="block truncate font-medium">{{ item.label }}</span>
					<span class="block truncate text-xs text-muted-fg">{{ item.description }}</span>
				</span>
			</template>
		</DomAutocomplete>
		<p class="rounded-2xl border border-border bg-secondary/40 p-3 text-xs text-muted-fg">
			Text value: <code class="font-mono text-fg">{{ value || 'Empty' }}</code>
		</p>
	</div>
</template>

Usage

Plain HTML

Use the headless custom element when you want autocomplete in plain HTML or another framework. The headless page includes a copyable HTML and JavaScript example.

View headless autocomplete

Props

Props

NameTypeDefaultDescription
v-modelstringCurrent text in the input.
optionsArray<{ value, label, ...meta }> | string[][]Suggestions. May be replaced as query results arrive.
placeholderstring'Search...'Input placeholder.
floatingMode'viewport' | 'anchor''viewport'Choose whether suggestions stay in the browser or follow the input while scrolling.
loadingbooleanfalseShow an inline spinner while async suggestions are being fetched.

Events

  • update:modelValueFired as the text changes.
  • queryFired as the user types. Use this to fetch suggestions.
  • selectFired when a suggestion is chosen. Receives the original item plus value, label, text, and query.
  • commitFired when Enter commits the current text.