aria-autocomplete
Describes the type of autocompletion behavior a combobox, textbox, or searchbox will use. Tells screen readers how input predictions will be presented to users.
Overview
The aria-autocomplete attribute describes the type of autocomplete behavior a text input will provide. It tells assistive technologies how suggestions or predictions will be presented as the user types.
This attribute is used on elements with role="combobox", role="textbox", or role="searchbox". It helps screen reader users understand what to expect when they start typing.
Required Companions
When using aria-autocomplete="list" or both, you typically need: aria-expanded, aria-haspopup="listbox", aria-controls, and aria-activedescendant for full accessibility.
Live Demo: Combobox with aria-autocomplete="list"
Try typing "a" to see filtered suggestions. Use arrow keys to navigate.
Screen reader announcement: "Search Fruits, combobox, autocomplete list, expanded, 15 items". When navigating options: "Apple, 1 of 15".
Attribute Values
noneNo autocomplete suggestions are provided. The element may have a popup list, but it shows all options regardless of what the user types. The list is static, not filtered.
listA list of suggestions appears in a popup as the user types. The user can select from the list or continue typing. This is the most common autocomplete pattern (like search suggestions).
inlineText is automatically completed inline within the input field itself. The suggested completion appears after the cursor, typically selected, so typing replaces it.
bothCombines inline completion AND a popup list. The best match appears inline while a full list of suggestions is shown in a popup. This provides maximum flexibility.
Code Examples
None (No Autocomplete)
<!-- aria-autocomplete="none" -->
<!-- No autocomplete suggestions provided -->
<label for="name">Name</label>
<input
type="text"
id="name"
role="combobox"
aria-autocomplete="none"
aria-expanded="false"
aria-haspopup="listbox"
/>
<!-- Use "none" when the input has a popup list
but doesn't filter or suggest based on input.
Example: A dropdown that shows all options regardless of typing -->List Autocomplete
<!-- aria-autocomplete="list" -->
<!-- Shows a list of suggestions that appear in a popup -->
<div class="combobox-container">
<label for="fruit">Favorite Fruit</label>
<input
type="text"
id="fruit"
role="combobox"
aria-autocomplete="list"
aria-expanded="true"
aria-controls="fruit-listbox"
aria-haspopup="listbox"
aria-activedescendant="fruit-option-1"
/>
<ul
id="fruit-listbox"
role="listbox"
aria-label="Fruit suggestions"
>
<li id="fruit-option-0" role="option">Apple</li>
<li id="fruit-option-1" role="option" aria-selected="true">
Apricot
</li>
<li id="fruit-option-2" role="option">Avocado</li>
</ul>
</div>
<!-- Screen reader: "Favorite Fruit, combobox, autocomplete list,
expanded, Apricot, option 2 of 3" -->Inline Autocomplete
<!-- aria-autocomplete="inline" -->
<!-- Text is auto-completed inline as user types -->
<label for="email">Email address</label>
<input
type="email"
id="email"
role="combobox"
aria-autocomplete="inline"
aria-expanded="false"
/>
<!-- Example behavior:
User types: "john"
Input shows: "john|@example.com" (completion selected)
The completion text is typically selected so typing
overwrites it. Less common than "list" or "both". -->Both (Inline + List)
<!-- aria-autocomplete="both" -->
<!-- Combines inline completion AND a popup list -->
<div class="combobox-container">
<label for="country">Country</label>
<input
type="text"
id="country"
role="combobox"
aria-autocomplete="both"
aria-expanded="true"
aria-controls="country-listbox"
aria-haspopup="listbox"
/>
<ul id="country-listbox" role="listbox">
<li role="option">United States</li>
<li role="option">United Kingdom</li>
<li role="option">United Arab Emirates</li>
</ul>
</div>
<!-- User types: "uni"
Input shows: "uni|ted States" (inline completion)
Popup shows: List of matching countries
This is like Google search: you see inline suggestion
AND a dropdown of options -->React Component
// React Combobox with Autocomplete
import { useState, useRef, useEffect } from 'react';
function Combobox({
label,
options,
autocomplete = 'list', // 'none' | 'list' | 'inline' | 'both'
onChange
}) {
const [query, setQuery] = useState('');
const [isOpen, setIsOpen] = useState(false);
const [activeIndex, setActiveIndex] = useState(-1);
const inputRef = useRef(null);
const listRef = useRef(null);
// Filter options based on query
const filteredOptions = options.filter(opt =>
opt.toLowerCase().includes(query.toLowerCase())
);
// Active descendant ID
const activeDescendant = activeIndex >= 0
? `option-${activeIndex}`
: undefined;
const handleKeyDown = (e) => {
switch (e.key) {
case 'ArrowDown':
e.preventDefault();
if (!isOpen) {
setIsOpen(true);
setActiveIndex(0);
} else {
setActiveIndex(prev =>
prev < filteredOptions.length - 1 ? prev + 1 : 0
);
}
break;
case 'ArrowUp':
e.preventDefault();
setActiveIndex(prev =>
prev > 0 ? prev - 1 : filteredOptions.length - 1
);
break;
case 'Enter':
e.preventDefault();
if (activeIndex >= 0 && filteredOptions[activeIndex]) {
selectOption(filteredOptions[activeIndex]);
}
break;
case 'Escape':
setIsOpen(false);
setActiveIndex(-1);
inputRef.current?.focus();
break;
}
};
const selectOption = (option) => {
setQuery(option);
setIsOpen(false);
setActiveIndex(-1);
onChange?.(option);
inputRef.current?.focus();
};
const handleInputChange = (e) => {
const value = e.target.value;
setQuery(value);
setIsOpen(value.length > 0);
setActiveIndex(-1);
};
return (
<div className="combobox">
<label htmlFor="combobox-input">{label}</label>
<input
ref={inputRef}
id="combobox-input"
type="text"
role="combobox"
aria-autocomplete={autocomplete}
aria-expanded={isOpen}
aria-controls="combobox-listbox"
aria-haspopup="listbox"
aria-activedescendant={activeDescendant}
value={query}
onChange={handleInputChange}
onKeyDown={handleKeyDown}
onFocus={() => query && setIsOpen(true)}
onBlur={() => setTimeout(() => setIsOpen(false), 200)}
/>
{isOpen && filteredOptions.length > 0 && (
<ul
ref={listRef}
id="combobox-listbox"
role="listbox"
aria-label={`${label} suggestions`}
>
{filteredOptions.map((option, index) => (
<li
key={option}
id={`option-${index}`}
role="option"
aria-selected={index === activeIndex}
onClick={() => selectOption(option)}
className={index === activeIndex ? 'active' : ''}
>
{option}
</li>
))}
</ul>
)}
</div>
);
}
// Usage
<Combobox
label="Search fruits"
options={['Apple', 'Banana', 'Cherry', 'Date']}
autocomplete="list"
onChange={(value) => console.log('Selected:', value)}
/>Best Practices
Use aria-autocomplete="list" for most search/filter autocomplete implementations
Always pair with aria-expanded, aria-haspopup, and aria-controls when using list/both
Use aria-activedescendant to track the currently highlighted option in the list
Implement arrow key navigation for moving through suggestions
Close the suggestions list on Escape and blur
Announce the number of suggestions for screen reader users
Don't use aria-autocomplete without proper role (combobox, textbox, searchbox)
Don't forget keyboard navigation—Enter to select, Escape to close
Don't use aria-autocomplete="inline" unless you actually implement inline completion
Don't confuse aria-autocomplete with the HTML autocomplete attribute (different purposes)

