Free-typing input with a single-select listbox of suggestions.
Autocomplete is a typing-first single-select. Use it when the user already knows what they want and just needs help completing the value (recipient lookup, tag suggestion, search-as-you-type). For shorter, browse-first option sets, prefer Combobox or Select.
Provide options up front and Autocomplete handles local filtering.
<Autocomplete
options={[
{ value: "apple", label: "Apple" },
{ value: "banana", label: "Banana" },
{ value: "cherry", label: "Cherry" }
]}
aria-label="Pick a fruit"
placeholder="Pick a fruit"
/>import {
Autocomplete,
type AutocompleteOption,
} from "@froggdesign/enter-ui-react";Type, use the arrow keys, and clear the query without losing input focus.
import { Search } from "lucide-react";
const [query, setQuery] = useState("");
<Autocomplete
aria-label="Find a component"
leadingIcon={<Search size={18} />}
inputValue={query}
onInputValueChange={setQuery}
onClear={() => setQuery("")}
clearLabel="Clear component search"
options={[
{ value: "button", label: "Button", description: "Actions" },
{ value: "card", label: "Card", description: "Foundations" },
{ value: "legacy", label: "Legacy control", disabled: true },
]}
/>The component owns icon spacing, the clear action, popup sizing, and pointer
states. Use these props directly without consumer styling overrides.
The clear action empties uncontrolled selection and text, emits
onInputValueChange("") and onSearchChange(""), invokes onClear, and returns
focus to the input. If value is controlled, reset that selected value in
onClear as well. onValueChange fires when an option is selected.
Pass disableLocalFilter and respond to onSearchChange or onInputValueChange from a debounced fetcher to plug an async data source. Re-render with the freshly loaded options.
const [results, setResults] = useState<AutocompleteOption[]>([]);
const [loading, setLoading] = useState(false);
<Autocomplete
options={results}
loading={loading}
disableLocalFilter
onSearchChange={(query) => {
setLoading(true);
debouncedSearch(query).then((data) => {
setResults(data);
setLoading(false);
});
}}
onValueChange={(value, option) => onPick(option)}
/>Provide a visible label or aria-label. The input follows the WAI-ARIA combobox
pattern with role="combobox", and suggestions use role="listbox" /
role="option". aria-activedescendant references only an available, enabled
suggestion. The empty and loading states use role="status".
ArrowDown highlights the first enabled suggestion; ArrowUp
starts at the last. Subsequent arrow keys wrap and skip disabled options.Enter selects the highlighted suggestion. It does not select while an IME
composition is active. allowCustomValue permits committing unhighlighted text.Escape closes the popup while keeping the typed query. Tab leaves the
control, and leaving the control closes the popup.The popup follows the input width and scrolls vertically for long option lists. Icon and clear spacing remain inside the field on narrow screens.
options, value, defaultValue, onValueChange.inputValue, defaultInputValue, onInputValueChange, onSearchChange.allowCustomValue for committing free-typed values with Enter.loading, emptyText, loadingText, disableLocalFilter.invalid, disabled, placeholder, rootClassName.leadingIcon?: ReactNode adds a decorative icon before the text.onClear?: () => void enables the clear action for nonempty text.clearLabel?: string defaults to "Clear input".defaultOpen?: boolean opens suggestions initially, including in previews.id, aria-label, and readOnly, are supported.Every exported component accepts className. EnterUI styles use .eui-* classes and --eui-* variables mapped from FroggDesign theme tokens.