Autocomplete’s value is the text itself: picking a suggestion replaces the text, and a form receives whatever is typed. When the value must be one of the items, use Select with searchable instead. Supply items as <option> children, and label the field with tp-field or label.
Matching
Prefix matching
Default density
Compact density
Restart from the initial state
Show the copyable source
<tp-field label="Country" description="Type the start of each word: un st" style="inline-size:100%;inline-size:100%;max-inline-size:22rem;margin-inline:auto">
<tp-autocomplete style="inline-size:100%" matching="prefix" placeholder="Search countries">
<option>United Kingdom</option>
<option>United States</option>
<option>United Arab Emirates</option>
<option>South Africa</option>
<option>South Korea</option>
<option>New Zealand</option>
</tp-autocomplete>
</tp-field>
The default fuzzy matching ranks results by relevance and tolerates typos, so “rasberry” still finds Raspberry. prefix, contains and exact keep the items in their given order and suit codes, names and lists where a typo match would be noise. Matched text is highlighted in every mode. limit keeps the
first results. filter ((item, query, text) => boolean) replaces matching with your own
predicate, filter = null shows every item, and filteredItems supplies the results yourself.
Groups
Grouped suggestions
Default density
Compact density
Restart from the initial state
Show the copyable source
<optgroup> labels sections of suggestions. show-trigger adds a button that opens the full list, and open-on-input-click opens it on click, which helps when people browse rather than type. Groups keep their labels while their matching suggestions are shown; groups without matches are hidden.
Completion
Inline completion
Default density
Compact density
Restart from the initial state
Show the copyable source
completion-mode="both" fills in the highlighted suggestion as you type, selecting the completed part so typing continues naturally. auto-highlight highlights the first suggestion, so Enter accepts it. show-clear adds a clear button.
Keywords
Searching hidden fields
Default density
Compact density
Restart from the initial state
Show the copyable source
The items property accepts strings, records and groups when the list comes from data. matchFields adds searchable text that is never displayed, such as aliases or keywords. Results can also come from a server through the source property.
Records
Ranking over several fields
Default density
Compact density
Restart from the initial state
Show the copyable source
<tp-field label="Help center" description="Try: refund, password, seats" style="inline-size:100%;max-inline-size:22rem;margin-inline:auto">
<tp-autocomplete style="inline-size:100%" id="autocomplete-articles" placeholder="Search articles"></tp-autocomplete>
</tp-field>
<script type="module">
import { createIndexSource } from '@tweakpad/ui';
const articles = [
{ title: 'Request a refund', summary: 'Refunds for annual plans within 30 days of purchase.' },
{ title: 'Reset your password', summary: 'Get a sign-in link by email when you forget your password.' },
{ title: 'Add or remove seats', summary: 'Change how many members your plan pays for.' },
{ title: 'Download invoices', summary: 'Receipts and refund credit notes for every billing period.' },
{ title: 'Turn on two-step sign-in', summary: 'Protect your password with an authenticator app.' },
];
await customElements.whenDefined('tp-autocomplete');
const autocomplete = document.querySelector('#autocomplete-articles');
autocomplete.itemToText = (article) => article.title;
autocomplete.source = createIndexSource(articles, {
fields: ['title', 'summary'],
boost: { title: 3 },
extract: (article, field) => article[field],
});
</script>
createIndexSource() builds the same typo-tolerant index the component uses, over any records you pass. Here it searches each article’s title and summary but weights the title three times, so “refund” lists Request a refund before the invoices article that only mentions it. itemToText names each record in the list and the field.
Server search
Search source
Default density
Compact density
Restart from the initial state
Show the copyable source
<tp-field label="Departure airport" description="Results arrive after a simulated 600 ms request." style="inline-size:100%;max-inline-size:22rem;margin-inline:auto">
<tp-autocomplete style="inline-size:100%" id="autocomplete-server" search-delay="250" placeholder="City or airport code"></tp-autocomplete>
</tp-field>
<script type="module">
const airports = [
'Amsterdam Schiphol (AMS)', 'Barcelona El Prat (BCN)', 'Berlin Brandenburg (BER)',
'Dublin (DUB)', 'Frankfurt (FRA)', 'Lisbon Humberto Delgado (LIS)', 'London Heathrow (LHR)',
'London Gatwick (LGW)', 'Madrid Barajas (MAD)', 'Milan Malpensa (MXP)', 'Munich (MUC)',
'Paris Charles de Gaulle (CDG)', 'Rome Fiumicino (FCO)', 'Vienna (VIE)', 'Zurich (ZRH)',
];
await customElements.whenDefined('tp-autocomplete');
document.querySelector('#autocomplete-server').source = {
// Stands in for fetch('/api/airports?q=' + query, { signal }).
search(query, { signal }) {
return new Promise((resolve, reject) => {
const timer = setTimeout(() => {
const text = query.trim().toLowerCase();
resolve(airports.filter((airport) => airport.toLowerCase().includes(text)).slice(0, 8));
}, 600);
signal.addEventListener('abort', () => {
clearTimeout(timer);
reject(signal.reason);
});
});
},
};
</script>
A source’s search(query, context) returns results directly or as a promise, in the order they should appear. search-delay waits for a pause in typing, and each new query aborts the previous one through context.signal. While a request is pending the list is marked busy and keeps the previous suggestions, or shows a loading row when there are none. createRequestSource() wraps a URL and a response mapper into a source for you.
A failure shows “Suggestions could not be
loaded.”.
Results may be plain items or hits { item, score?, terms?, matches? }. Matched ranges come from
matches ([{ field: 'text', ranges: [[start, end], …] }]), else from terms, else from the
typed words, so a server that reports what matched is highlighted exactly.
Any engine plugs in as a source; the library depends on none of them. For example, with an engine
that returns ranked items and match positions:
With name, the form receives the text, including text that matches no suggestion. required requires text. Enter with nothing highlighted submits the form, and Escape first closes the suggestions, then clears the text. submit-on-item-click submits as soon as a suggestion is picked, which suits a search box that has nothing else to fill in.
Down and Up open the suggestions and move through them; Home and End go to the first and last.
Enter accepts the highlighted suggestion; with nothing highlighted the text stands and the owning
form submits. Escape first removes a completion, then closes, and while closed clears the text.
Typing opens the suggestions; clearing the text closes them unless open-on-input-click is set.
Composition (IME) input never navigates or accepts.
Form reset restores default-value.
Accessibility
The input is a combobox with aria-autocomplete matching the completion mode; DOM focus stays in
it while the highlight moves through the listbox (aria-activedescendant). Suggestions are options
without a selected state. A polite status region announces the result count, loading and errors,
in the messages texts.
API Reference
Every element also accepts motion-policy.
Events
EventTypeDescriptiontp-value-changeTpValueChangeEvent<unknown>Cancelable proposal of a new value, before it commits; detail.value, detail.previousValue and detail.reason.tp-field-valueCustomEvent<{ value: unknown; previousValue: unknown; reason: ChangeReason; }>After a value commits; an enclosing Field tracks its dirty state from it.tp-open-changeTpSurfaceOpenChangeEventCancelable proposal to open or close the list; detail.value and detail.reason.tp-open-change-completeCustomEvent<{ open: boolean; }>{ open } after the list finishes opening or closing.tp-search-statusCustomEvent<{ status: SearchStatus; query: string; total: number; }>{ status, query, total } as a search source loads, settles or fails.tp-search-errorCustomEvent<{ error: unknown; query: string; }>{ error, query } when a search source fails.
Slots
SlotDescriptiondefaultNative option, optgroup and hr children, or Select Options, declaring the choices when items is unset.emptyShown in place of the options when none matches the query.
CSS parts
PartDescription::part(select-action-host)The element around each trigger, clear and chip-remove button; style the buttons through their own parts.