Component
<dom-autocomplete>
custom elementFree-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
| Name | Scope | Description |
|---|---|---|
| #input | — | The text input. Gets role="combobox" and aria-controls wired automatically. |
| #list | — | Optional suggestions. The list may be updated by a framework or server lookup. |
Attributes
| Name | Type | Description |
|---|---|---|
| value | string | Current text value. |
| open | boolean | Reflects whether suggestions are visible. |
| placement | string | Preferred 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-id | string | Id of an external or teleported suggestion list. |
From dom-autocomplete.__doc.attributes.
Events
| Name | Payload | Description |
|---|---|---|
| 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