Component

<dom-autocomplete>

custom element

Free-text autocomplete. Suggestions are optional; typed values are valid and Enter commits the current text.

Demo

Styled datalist

A free-text input with styled suggestions. Typing emits query events; selecting a suggestion emits a separate select event.

basic.htmlhtml
<div class="flex w-full max-w-sm flex-col gap-2">
	<dom-autocomplete id="people-autocomplete" class="relative block w-full">
		<input
			slot="input"
			type="text"
			placeholder="Search or type anything…"
			class="h-10 w-full rounded-full border border-border bg-background px-4 text-sm text-fg outline-none focus:ring-2 focus:ring-ring/40"
		/>
		<ul slot="list" class="z-50 max-h-[min(12rem,var(--dom-floating-available-height))] overflow-auto rounded-2xl border border-border bg-background p-1 shadow-lg">
			<li data-value="1" data-label="Ada Lovelace" data-email="ada@example.com" class="cursor-pointer rounded-xl px-3 py-2 text-sm text-fg transition hover:bg-secondary data-[active]:bg-secondary aria-selected:bg-secondary">Ada Lovelace</li>
			<li data-value="2" data-label="Grace Hopper" data-email="grace@example.com" class="cursor-pointer rounded-xl px-3 py-2 text-sm text-fg transition hover:bg-secondary data-[active]:bg-secondary aria-selected:bg-secondary">Grace Hopper</li>
			<li data-value="3" data-label="Katherine Johnson" data-email="katherine@example.com" class="cursor-pointer rounded-xl px-3 py-2 text-sm text-fg transition hover:bg-secondary data-[active]:bg-secondary aria-selected:bg-secondary">Katherine Johnson</li>
		</ul>
	</dom-autocomplete>
	<p class="text-xs text-muted-fg">Typed text: <code id="people-query" class="text-fg">—</code></p>
	<p class="text-xs text-muted-fg">Selected: <code id="people-selected" class="text-fg">—</code></p>
</div>

<script type="module">
	import '@getdom/studio/headless/autocomplete.js';

	const autocomplete = document.getElementById('people-autocomplete');
	const query = document.getElementById('people-query');
	const selected = document.getElementById('people-selected');

	autocomplete.addEventListener('dom:input', (event) => {
		query.textContent = event.detail.value || '—';
	});

	autocomplete.addEventListener('dom:select', (event) => {
		const option = event.detail.option;
		selected.textContent = `${event.detail.label} (${option.dataset.email})`;
	});
</script>

Usage

Plain HTML

Register every <dom-*> in one import: import '@getdom/studio/headless'.

Slots

NameScopeDescription
#inputThe text input. Gets role="combobox" and aria-controls wired automatically.
#listOptional suggestions. The list may be updated by a framework or server lookup.

Attributes

NameTypeDescription
valuestringCurrent text value.
openbooleanReflects whether suggestions are visible.
placementstringPreferred floating placement before collision handling.
floating-mode'viewport' | 'anchor'viewport keeps suggestions inside the browser; anchor keeps them attached to the input while scrolling.
data-menu-idstringId of an external or teleported suggestion list.

From dom-autocomplete.__doc.attributes.

Events

NamePayloadDescription
dom:input{ value }Fired whenever the text value changes.
dom:query{ query }Fired whenever the user types. Useful for server lookups.
dom:select{ value, label, option }Fired when a suggestion is selected.
dom:custom{ value, label }Cancelable event fired when Enter commits free text.
dom:change{ value, option, custom }Fired when text or a suggestion is committed.

Names auto-detected from defineEmits and source emit() calls; payload and description from __doc.events when present.

Related

See also

← Headless overview