Autocomplete
Autocomplete components provide real-time typeahead suggestions as users type in a text field.
Overview
Autocomplete enhances text input fields by providing dynamic suggestions as users type. It can be applied to various input components including single selects, multi-selects, and search fields to help users quickly find and select options from large datasets. The component filters and displays relevant suggestions based on the user’s input, reducing typing effort and improving accuracy.
Usage
forge-autocomplete wraps a text field and filters a list of options as the user types, through mode, multiple, debounce, and emptyMessage. Use it when a dropdown has too many options to scan comfortably; for a short, finite list, a select is simpler and doesn’t require typing.
Rules
Modes
mode has two values: default (the common case) manages selection state for you as a form control. stateless doesn’t track a selection at all — use it when you just want the typing/filtering behavior and intend to handle selection yourself.
Initial value
Pre-populating a bound value on load needs the matching option available to show its label, not just the raw value. Either pass the full IOption object (value and label) to the value property directly, or return it from the filter callback’s second parameter — the autocomplete calls the callback with that parameter specifically when it can’t find a matching option already in its current list, so you can fetch it from wherever the rest of your options come from.
Basic filtering
Wrap a forge-text-field (typically with popover-icon and show-clear) in a forge-autocomplete to filter its dropdown options as the user types.
A text field filters its dropdown options as the user types.
<forge-autocomplete class="w-[256px]">
<forge-text-field show-clear popover-icon>
<input type="text" id="state" autocomplete="off" role="combobox" aria-live="polite" aria-atomic aria-haspopup aria-autocomplete="list" aria-controls="forge-aria-controls-placeholder">
<label for="state" aria-label="choose state" slot="label">
Choose state
</label>
</forge-text-field>
</forge-autocomplete>
<script type="module">
const states = [
{ label: "Alabama", value: "AL" },
{ label: "Alaska", value: "AK" },
{ label: "Arizona", value: "AZ" },
{ label: "Arkansas", value: "AR" },
{ label: "California", value: "CA" },
{ label: "Colorado", value: "CO" },
{ label: "Connecticut", value: "CT" },
{ label: "Delaware", value: "DE" },
{ label: "Florida", value: "FL" },
{ label: "Georgia", value: "GA" },
{ label: "Hawaii", value: "HI" },
{ label: "Idaho", value: "ID" },
{ label: "Illinois", value: "IL" },
{ label: "Indiana", value: "IN" },
{ label: "Iowa", value: "IA" },
{ label: "Kansas", value: "KS" },
{ label: "Kentucky", value: "KY" },
{ label: "Louisiana", value: "LA" },
{ label: "Maine", value: "ME" },
{ label: "Maryland", value: "MD" },
{ label: "Massachusetts", value: "MA" },
{ label: "Michigan", value: "MI" },
{ label: "Minnesota", value: "MN" },
{ label: "Mississippi", value: "MS" },
{ label: "Missouri", value: "MO" },
{ label: "Montana", value: "MT" },
{ label: "Nebraska", value: "NE" },
{ label: "Nevada", value: "NV" },
{ label: "New Hampshire", value: "NH" },
{ label: "New Jersey", value: "NJ" },
{ label: "New Mexico", value: "NM" },
{ label: "New York", value: "NY" },
{ label: "North Carolina", value: "NC" },
{ label: "North Dakota", value: "ND" },
{ label: "Ohio", value: "OH" },
{ label: "Oklahoma", value: "OK" },
{ label: "Oregon", value: "OR" },
{ label: "Pennsylvania", value: "PA" },
{ label: "Rhode Island", value: "RI" },
{ label: "South Carolina", value: "SC" },
{ label: "South Dakota", value: "SD" },
{ label: "Tennessee", value: "TN" },
{ label: "Texas", value: "TX" },
{ label: "Utah", value: "UT" },
{ label: "Vermont", value: "VT" },
{ label: "Virginia", value: "VA" },
{ label: "Washington", value: "WA" },
{ label: "West Virginia", value: "WV" },
{ label: "Wisconsin", value: "WI" },
{ label: "Wyoming", value: "WY" }
];
const filter = (filterText) => states.filter((state) => state.label.toLowerCase().includes(filterText.toLowerCase()));
const autocomplete = document.querySelector("forge-autocomplete");
if (autocomplete) {
autocomplete.filter = filter;
}
</script>Infinite scroll
Set observe-scroll to fire forge-autocomplete-scrolled-bottom as the user nears the bottom of the dropdown, so more options can be appended with appendOptions() instead of loading the entire set up front.
observe-scroll fires an event near the bottom of the dropdown to load more options.
<forge-autocomplete observe-scroll class="w-[320px]">
<forge-text-field popover-icon>
<input
type="text"
id="state"
autocomplete="off"
role="combobox"
aria-live="polite"
aria-atomic
aria-haspopup
aria-autocomplete="list"
aria-controls="forge-aria-controls-placeholder" />
<label for="state" aria-label="choose state" slot="label">
Choose state
</label>
</forge-text-field>
</forge-autocomplete>
<script type="module">
const countries = [
{ label: "Afghanistan", value: "AF" },
{ label: "Albania", value: "AL" },
{ label: "Algeria", value: "DZ" },
{ label: "Andorra", value: "AD" },
{ label: "Angola", value: "AO" },
{ label: "Antigua and Barbuda", value: "AG" },
{ label: "Argentina", value: "AR" },
{ label: "Armenia", value: "AM" },
{ label: "Australia", value: "AU" },
{ label: "Austria", value: "AT" },
{ label: "Azerbaijan", value: "AZ" },
{ label: "Bahamas", value: "BS" },
{ label: "Bahrain", value: "BH" },
{ label: "Bangladesh", value: "BD" },
{ label: "Barbados", value: "BB" },
{ label: "Belarus", value: "BY" },
{ label: "Belgium", value: "BE" },
{ label: "Belize", value: "BZ" },
{ label: "Benin", value: "BJ" },
{ label: "Bhutan", value: "BT" },
{ label: "Bolivia", value: "BO" },
{ label: "Bosnia and Herzegovina", value: "BA" },
{ label: "Botswana", value: "BW" },
{ label: "Brazil", value: "BR" },
{ label: "Brunei", value: "BN" },
{ label: "Bulgaria", value: "BG" },
{ label: "Burkina Faso", value: "BF" },
{ label: "Burundi", value: "BI" },
{ label: "Cabo Verde", value: "CV" },
{ label: "Cambodia", value: "KH" },
{ label: "Cameroon", value: "CM" },
{ label: "Canada", value: "CA" },
{ label: "Central African Republic", value: "CF" },
{ label: "Chad", value: "TD" },
{ label: "Chile", value: "CL" },
{ label: "China", value: "CN" },
{ label: "Colombia", value: "CO" },
{ label: "Comoros", value: "KM" },
{ label: "Congo", value: "CG" },
{ label: "Costa Rica", value: "CR" },
{ label: "C\xF4te d'Ivoire", value: "CI" },
{ label: "Croatia", value: "HR" },
{ label: "Cuba", value: "CU" },
{ label: "Cyprus", value: "CY" },
{ label: "Czechia", value: "CZ" },
{ label: "Democratic Republic of the Congo", value: "CD" },
{ label: "Denmark", value: "DK" },
{ label: "Djibouti", value: "DJ" },
{ label: "Dominica", value: "DM" },
{ label: "Dominican Republic", value: "DO" },
{ label: "Ecuador", value: "EC" },
{ label: "Egypt", value: "EG" },
{ label: "El Salvador", value: "SV" },
{ label: "Equatorial Guinea", value: "GQ" },
{ label: "Eritrea", value: "ER" },
{ label: "Estonia", value: "EE" },
{ label: "Eswatini", value: "SZ" },
{ label: "Ethiopia", value: "ET" },
{ label: "Fiji", value: "FJ" },
{ label: "Finland", value: "FI" },
{ label: "France", value: "FR" },
{ label: "Gabon", value: "GA" },
{ label: "Gambia", value: "GM" },
{ label: "Georgia", value: "GE" },
{ label: "Germany", value: "DE" },
{ label: "Ghana", value: "GH" },
{ label: "Greece", value: "GR" },
{ label: "Grenada", value: "GD" },
{ label: "Guatemala", value: "GT" },
{ label: "Guinea", value: "GN" },
{ label: "Guinea-Bissau", value: "GW" },
{ label: "Guyana", value: "GY" },
{ label: "Haiti", value: "HT" },
{ label: "Honduras", value: "HN" },
{ label: "Hungary", value: "HU" },
{ label: "Iceland", value: "IS" },
{ label: "India", value: "IN" },
{ label: "Indonesia", value: "ID" },
{ label: "Iran", value: "IR" },
{ label: "Iraq", value: "IQ" },
{ label: "Ireland", value: "IE" },
{ label: "Israel", value: "IL" },
{ label: "Italy", value: "IT" },
{ label: "Jamaica", value: "JM" },
{ label: "Japan", value: "JP" },
{ label: "Jordan", value: "JO" },
{ label: "Kazakhstan", value: "KZ" },
{ label: "Kenya", value: "KE" },
{ label: "Kiribati", value: "KI" },
{ label: "Kuwait", value: "KW" },
{ label: "Kyrgyzstan", value: "KG" },
{ label: "Laos", value: "LA" },
{ label: "Latvia", value: "LV" },
{ label: "Lebanon", value: "LB" },
{ label: "Lesotho", value: "LS" },
{ label: "Liberia", value: "LR" },
{ label: "Libya", value: "LY" },
{ label: "Liechtenstein", value: "LI" },
{ label: "Lithuania", value: "LT" },
{ label: "Luxembourg", value: "LU" },
{ label: "Madagascar", value: "MG" },
{ label: "Malawi", value: "MW" },
{ label: "Malaysia", value: "MY" },
{ label: "Maldives", value: "MV" },
{ label: "Mali", value: "ML" },
{ label: "Malta", value: "MT" },
{ label: "Marshall Islands", value: "MH" },
{ label: "Mauritania", value: "MR" },
{ label: "Mauritius", value: "MU" },
{ label: "Mexico", value: "MX" },
{ label: "Micronesia", value: "FM" },
{ label: "Moldova", value: "MD" },
{ label: "Monaco", value: "MC" },
{ label: "Mongolia", value: "MN" },
{ label: "Montenegro", value: "ME" },
{ label: "Morocco", value: "MA" },
{ label: "Mozambique", value: "MZ" },
{ label: "Myanmar", value: "MM" },
{ label: "Namibia", value: "NA" },
{ label: "Nauru", value: "NR" },
{ label: "Nepal", value: "NP" },
{ label: "Netherlands", value: "NL" },
{ label: "New Zealand", value: "NZ" },
{ label: "Nicaragua", value: "NI" },
{ label: "Niger", value: "NE" },
{ label: "Nigeria", value: "NG" },
{ label: "North Korea", value: "KP" },
{ label: "North Macedonia", value: "MK" },
{ label: "Norway", value: "NO" },
{ label: "Oman", value: "OM" },
{ label: "Pakistan", value: "PK" },
{ label: "Palau", value: "PW" },
{ label: "Palestine", value: "PS" },
{ label: "Panama", value: "PA" },
{ label: "Papua New Guinea", value: "PG" },
{ label: "Paraguay", value: "PY" },
{ label: "Peru", value: "PE" },
{ label: "Philippines", value: "PH" },
{ label: "Poland", value: "PL" },
{ label: "Portugal", value: "PT" },
{ label: "Qatar", value: "QA" },
{ label: "Romania", value: "RO" },
{ label: "Russia", value: "RU" },
{ label: "Rwanda", value: "RW" },
{ label: "Saint Kitts and Nevis", value: "KN" },
{ label: "Saint Lucia", value: "LC" },
{ label: "Saint Vincent and the Grenadines", value: "VC" },
{ label: "Samoa", value: "WS" },
{ label: "San Marino", value: "SM" },
{ label: "Sao Tome and Principe", value: "ST" },
{ label: "Saudi Arabia", value: "SA" },
{ label: "Senegal", value: "SN" },
{ label: "Serbia", value: "RS" },
{ label: "Seychelles", value: "SC" },
{ label: "Sierra Leone", value: "SL" },
{ label: "Singapore", value: "SG" },
{ label: "Slovakia", value: "SK" },
{ label: "Slovenia", value: "SI" },
{ label: "Solomon Islands", value: "SB" },
{ label: "Somalia", value: "SO" },
{ label: "South Africa", value: "ZA" },
{ label: "South Korea", value: "KR" },
{ label: "South Sudan", value: "SS" },
{ label: "Spain", value: "ES" },
{ label: "Sri Lanka", value: "LK" },
{ label: "Sudan", value: "SD" },
{ label: "Suriname", value: "SR" },
{ label: "Sweden", value: "SE" },
{ label: "Switzerland", value: "CH" },
{ label: "Syria", value: "SY" },
{ label: "Tajikistan", value: "TJ" },
{ label: "Tanzania", value: "TZ" },
{ label: "Thailand", value: "TH" },
{ label: "Timor-Leste", value: "TL" },
{ label: "Togo", value: "TG" },
{ label: "Tonga", value: "TO" },
{ label: "Trinidad and Tobago", value: "TT" },
{ label: "Tunisia", value: "TN" },
{ label: "T\xFCrkiye", value: "TR" },
{ label: "Turkmenistan", value: "TM" },
{ label: "Tuvalu", value: "TV" },
{ label: "Uganda", value: "UG" },
{ label: "Ukraine", value: "UA" },
{ label: "United Arab Emirates", value: "AE" },
{ label: "United Kingdom", value: "GB" },
{ label: "United States", value: "US" },
{ label: "Uruguay", value: "UY" },
{ label: "Uzbekistan", value: "UZ" },
{ label: "Vanuatu", value: "VU" },
{ label: "Vatican City", value: "VA" },
{ label: "Venezuela", value: "VE" },
{ label: "Vietnam", value: "VN" },
{ label: "Yemen", value: "YE" },
{ label: "Zambia", value: "ZM" },
{ label: "Zimbabwe", value: "ZW" }
];
const PAGE_SIZE = 10;
const autocomplete = document.querySelector("forge-autocomplete");
if (autocomplete) {
let filteredCountries = [];
let currentOptions = [];
const filter = (filterText) => {
const needle = filterText.toLowerCase();
filteredCountries = countries.filter((country) => country.label.toLowerCase().includes(needle));
currentOptions = filteredCountries.slice(0, PAGE_SIZE);
return currentOptions;
};
autocomplete.filter = filter;
autocomplete.addEventListener("forge-autocomplete-scrolled-bottom", () => {
if (currentOptions.length >= filteredCountries.length) {
return;
}
const nextOptions = filteredCountries.slice(currentOptions.length, currentOptions.length + PAGE_SIZE);
currentOptions = [...currentOptions, ...nextOptions];
autocomplete.appendOptions(nextOptions);
});
}
</script>Multi-select
Set multiple to let a user select more than one option instead of replacing the previous selection.
Multiple lets a user select more than one option.
<forge-autocomplete multiple class="w-[256px]">
<forge-text-field show-clear popover-icon>
<input type="text" id="autocomplete-multiselect" autocomplete="off" role="combobox" aria-live="polite" aria-atomic aria-haspopup aria-autocomplete="list" aria-controls="forge-aria-controls-placeholder">
<label for="autocomplete-multiselect" slot="label">
Choose states
</label>
</forge-text-field>
</forge-autocomplete>
<script type="module">
const states = [
{ label: "Alabama", value: "AL" },
{ label: "Alaska", value: "AK" },
{ label: "Arizona", value: "AZ" },
{ label: "Arkansas", value: "AR" },
{ label: "California", value: "CA" },
{ label: "Colorado", value: "CO" },
{ label: "Connecticut", value: "CT" },
{ label: "Delaware", value: "DE" },
{ label: "Florida", value: "FL" },
{ label: "Georgia", value: "GA" },
{ label: "Hawaii", value: "HI" },
{ label: "Idaho", value: "ID" },
{ label: "Illinois", value: "IL" },
{ label: "Indiana", value: "IN" },
{ label: "Iowa", value: "IA" },
{ label: "Kansas", value: "KS" },
{ label: "Kentucky", value: "KY" },
{ label: "Louisiana", value: "LA" },
{ label: "Maine", value: "ME" },
{ label: "Maryland", value: "MD" },
{ label: "Massachusetts", value: "MA" },
{ label: "Michigan", value: "MI" },
{ label: "Minnesota", value: "MN" },
{ label: "Mississippi", value: "MS" },
{ label: "Missouri", value: "MO" },
{ label: "Montana", value: "MT" },
{ label: "Nebraska", value: "NE" },
{ label: "Nevada", value: "NV" },
{ label: "New Hampshire", value: "NH" },
{ label: "New Jersey", value: "NJ" },
{ label: "New Mexico", value: "NM" },
{ label: "New York", value: "NY" },
{ label: "North Carolina", value: "NC" },
{ label: "North Dakota", value: "ND" },
{ label: "Ohio", value: "OH" },
{ label: "Oklahoma", value: "OK" },
{ label: "Oregon", value: "OR" },
{ label: "Pennsylvania", value: "PA" },
{ label: "Rhode Island", value: "RI" },
{ label: "South Carolina", value: "SC" },
{ label: "South Dakota", value: "SD" },
{ label: "Tennessee", value: "TN" },
{ label: "Texas", value: "TX" },
{ label: "Utah", value: "UT" },
{ label: "Vermont", value: "VT" },
{ label: "Virginia", value: "VA" },
{ label: "Washington", value: "WA" },
{ label: "West Virginia", value: "WV" },
{ label: "Wisconsin", value: "WI" },
{ label: "Wyoming", value: "WY" }
];
const filter = (filterText) => states.filter((state) => state.label.toLowerCase().includes(filterText.toLowerCase()));
const autocomplete = document.querySelector("forge-autocomplete");
if (autocomplete) {
autocomplete.filter = filter;
}
</script>Empty state
Set emptyMessage to show custom text in the dropdown when no options match the current filter.
An empty-message shows when no options match the filter. Search for something not in the list to see the empty state
<forge-autocomplete class="w-[256px]">
<forge-text-field show-clear popover-icon>
<input type="text" id="autocomplete-emptystate" autocomplete="off" role="combobox" aria-live="polite" aria-atomic aria-haspopup aria-autocomplete="list" aria-controls="forge-aria-controls-placeholder">
<label for="autocomplete-emptystate" slot="label">
Choose state
</label>
</forge-text-field>
</forge-autocomplete>
<script type="module">
const states = [
{ label: "Alabama", value: "AL" },
{ label: "Alaska", value: "AK" },
{ label: "Arizona", value: "AZ" },
{ label: "Arkansas", value: "AR" },
{ label: "California", value: "CA" }
];
const filter = (filterText) => states.filter((state) => state.label.toLowerCase().includes(filterText.toLowerCase()));
const autocomplete = document.querySelector("forge-autocomplete");
if (autocomplete) {
autocomplete.filter = filter;
autocomplete.emptyStateBuilder = (filterText) => {
const el = document.createElement("div");
el.innerHTML = `<strong>No matches for "${filterText}"</strong><br>Try a different search term.`;
return el;
};
}
</script>Autocomplete components provide real-time typeahead suggestions as users type in a text field. Use autocompletes to help users quickly find and select from a list of options, improving form usability and data accuracy.
import "@tylertech/forge/autocomplete";| Property | Attribute | Type | Default | Description |
|---|---|---|---|---|
mode | mode | `${AutocompleteMode}` | 'default' | Gets/sets the interaction mode. |
multiple | multiple | boolean | false | Gets/sets the multi-select state. |
value | — | any | — | Gets/sets the value. |
debounce | debounce | number | 500 | Gets/sets the debounce delay (milliseconds) for keyboard events. |
filterOnFocus | filter-on-focus | boolean | true | Gets/sets filter on focus settings which controls whether the dropdown displays automatically when focused. |
filterFocusFirst | filter-focus-first | boolean | true | Gets/sets whether the first option in the dropdown will be focused automatically when opened or not. |
selectFirstOptionOnBlur | select-first-option-on-blur | boolean | false | Determines whether the first available option should be selected automatically when blurring mid-filter. |
allowUnmatched | allow-unmatched | boolean | false | Controls whether unmatched text entered by the user will stay visible an option in the dropdown is not found. |
popupTarget | popup-target | string | — | Gets/sets the selector that will be used to find an element to attach the popup to. Defaults to the input element. |
filterText | — | string | — | Gets/sets the filter text. Setting the filter text only applies when allowUnmatched is enabled. |
optionBuilder | — | AutocompleteOptionBuilder | null | undefined | — | Sets the option builder callback that will be executed when building the option list in the dropdown. |
filter | — | AutocompleteFilterCallback | null | undefined | — | Sets the filter callback that will be executed when fetching options for the autocomplete dropdown. The callback is also invoked to resolve the display label for an already-selected value (e.g. on initialization, or via `forceFilter()`) by calling it with an empty `filterText` and the current `value` as its second argument. Implementations must handle this case by returning the matching option(s) for `value`, or the selected text will fail to resolve and appear blank. |
selectedTextBuilder | — | AutocompleteSelectedTextBuilder | — | Sets the selected text builder callback that will be executed when getting the selected text. |
open | open | boolean | false | Controls the open state of the dropdown. |
matchKey | match-key | string | null | undefined | — | Gets/sets the property key to match the value to an option. |
isInitialized | — | boolean | — | Returns whether the component has been initialized or not yet. |
popupElement | — | HTMLElement | null | — | Gets the currently active popup element when the dropdown is open. |
beforeValueChange | — | (value: any) => boolean | Promise<boolean> | — | Sets the callback to be executed when the user selects an option, before the UI is updated to allow for validation. |
emptyMessage | empty-message | string | null | undefined | — | Gets/sets the message displayed when the filter returns no results. |
emptyStateBuilder | — | AutocompleteEmptyStateBuilder | null | undefined | — | Sets the callback to build custom empty state content when the filter returns no results. |
popupClasses | popup-classes | string | string[] | — | Gets/sets the list of classes to apply to the popup element. |
popupHeaderBuilder | — | ListDropdownHeaderBuilder | — | Gets/sets the callback function for generating header content within the popup. |
popupFooterBuilder | — | ListDropdownFooterBuilder | — | Gets/sets the callback function for generating header content within the popup. |
syncPopupWidth | sync-popup-width | boolean | false | Gets/sets whether the popup width is synchronized with the popup target width. |
optionLimit | option-limit | number | 0 | Gets/sets the maximum number of options to display in the dropdown. |
observeScroll | observe-scroll | boolean | false | Controls the observation of scroll events on the dropdown. |
observeScrollThreshold | observe-scroll-threshold | number | 0 | The number of pixels from the bottom to trigger the scroll bottom event. Only applicable if `observeScroll` is true. |
constrainPopupWidth | constrain-popup-width | boolean | true | Gets/sets whether the popup width will be constrained to a max width of the viewport width (default: `100vw`). |
wrapOptionText | wrap-option-text | boolean | false | Gets/sets whether the options will wrap their text or not. This only applies if `constrainPopupWidth` is `true`, if there is an explicit width set via CSS. |
popoverPlacement | popover-placement | OverlayPlacement | 'bottom' | Gets/sets the placement of the popover. |
popoverOffset | popover-offset | IOverlayOffset | — | Gets/sets the offset of the popover. |
popoverFlip | popover-flip | OverlayFlipState | 'auto' | Gets/sets the flip state of the popover. |
popoverShift | popover-shift | OverlayShiftState | 'auto' | Gets/sets whether the popover should shift to fit within the viewport. |
popoverFallbackPlacements | popover-fallback-placements | PositionPlacement[] | null | — | Gets/sets the fallback placements of the popover. |
| Name | Type | Description |
|---|---|---|
forge-autocomplete-change | CustomEvent<any> | Fired when the value changes. |
forge-autocomplete-select | CustomEvent<IAutocompleteSelectEventData> | Fired when an option is selected. Only applies when in "stateless" `mode`. |
forge-autocomplete-scrolled-bottom | CustomEvent<void> | Fired when the dropdown is scrolled to the bottom. Only applies when `observe-scroll` is enabled. |
| Name | Returns | Description |
|---|---|---|
appendOptions(options) | void | Adds options to the dropdown while it is open. Has no effect if the dropdown is closed. |
openDropdown() | void | Opens the dropdown. |
closeDropdown() | void | Closes the dropdown. |
forceFilter(opts) | void | Forces the filter callback to be executed to update the current selection state with new options. This invokes the `filter` callback with the current `value` (and an empty filter text) so it can resolve and return the matching option(s), allowing the selected text to be updated to their label. |
Keyboard shortcuts
| Key | Action |
|---|---|
| Down / Arrow Down | Opens the dropdown and activates the first option |
| Arrow Up / Arrow Down | Moves through the list of options |
| Enter | Selects the active option |
| Home / End | Jumps to the first or last option |
| Tab | Single-select: selects the active option and closes the dropdown |
| Escape | Closes an open dropdown |
| Backspace / Delete | Edits the input’s text; clears a single-select value when the input is empty |
Screen reader behavior
The input automatically receives role="combobox", aria-live, and aria-owns. You’re still responsible for labeling it yourself — with a <label>, aria-label, or aria-labelledby — the component doesn’t provide one for you.
Verify you can tab into the autocomplete and reach every option in the dropdown using only the keyboard.