The Autocomplete component provides an input field that shows suggestions as the user types, perfect for search boxes and assisted input.
Installation
npx shadcn@latest add @eo-n/autocomplete
Install dependencies
Install the required packages:npm install @base-ui/react
Copy component code
Copy and paste the autocomplete component code into your project at components/ui/autocomplete.tsx.
Install Input component
This component requires the Input component:npx shadcn@latest add @eo-n/input
Update imports
Update the import paths to match your project setup.
import {
Autocomplete,
AutocompleteContent,
AutocompleteEmpty,
AutocompleteInput,
AutocompleteItem,
AutocompleteList,
} from "@/components/ui/autocomplete";
interface Fruit {
id: string;
value: string;
}
const fruits: Fruit[] = [
{ id: "a", value: "Apple" },
{ id: "b", value: "Banana" },
{ id: "c", value: "Cherry" },
{ id: "d", value: "Durian" },
];
export default function Example() {
return (
<Autocomplete items={fruits}>
<AutocompleteInput placeholder="Search fruits..." />
<AutocompleteContent>
<AutocompleteEmpty>No fruits found.</AutocompleteEmpty>
<AutocompleteList>
{(fruit: Fruit) => (
<AutocompleteItem key={fruit.id} value={fruit}>
{fruit.value}
</AutocompleteItem>
)}
</AutocompleteList>
</AutocompleteContent>
</Autocomplete>
);
}
Examples
Default
<Autocomplete items={fruits}>
<AutocompleteInput placeholder="Type to search..." />
<AutocompleteContent>
<AutocompleteEmpty>No results found.</AutocompleteEmpty>
<AutocompleteList>
{(fruit: Fruit) => (
<AutocompleteItem key={fruit.id} value={fruit}>
{fruit.value}
</AutocompleteItem>
)}
</AutocompleteList>
</AutocompleteContent>
</Autocomplete>
Disabled
<Autocomplete items={fruits} disabled>
<AutocompleteInput placeholder="Disabled autocomplete" />
<AutocompleteContent>
<AutocompleteList>
{(fruit: Fruit) => (
<AutocompleteItem key={fruit.id} value={fruit}>
{fruit.value}
</AutocompleteItem>
)}
</AutocompleteList>
</AutocompleteContent>
</Autocomplete>
Open On Input Click
<Autocomplete items={fruits} openOnClick>
<AutocompleteInput placeholder="Click to open..." />
<AutocompleteContent>
<AutocompleteList>
{(fruit: Fruit) => (
<AutocompleteItem key={fruit.id} value={fruit}>
{fruit.value}
</AutocompleteItem>
)}
</AutocompleteList>
</AutocompleteContent>
</Autocomplete>
With Input Group
import { Search } from "lucide-react";
<div className="relative">
<Search className="absolute left-3 top-3 size-4 text-muted-foreground" />
<Autocomplete items={fruits}>
<AutocompleteInput className="pl-9" placeholder="Search..." />
<AutocompleteContent>
<AutocompleteList>
{(fruit: Fruit) => (
<AutocompleteItem key={fruit.id} value={fruit}>
{fruit.value}
</AutocompleteItem>
)}
</AutocompleteList>
</AutocompleteContent>
</Autocomplete>
</div>
Async Search
import { useState, useEffect } from "react";
import { AutocompleteStatus } from "@/components/ui/autocomplete";
function AsyncAutocomplete() {
const [items, setItems] = useState<Fruit[]>([]);
const [loading, setLoading] = useState(false);
const [query, setQuery] = useState("");
useEffect(() => {
if (query) {
setLoading(true);
// Simulate API call
setTimeout(() => {
const filtered = fruits.filter((f) =>
f.value.toLowerCase().includes(query.toLowerCase())
);
setItems(filtered);
setLoading(false);
}, 300);
} else {
setItems([]);
}
}, [query]);
return (
<Autocomplete items={items}>
<AutocompleteInput
placeholder="Type to search..."
value={query}
onValueChange={setQuery}
/>
<AutocompleteContent>
<AutocompleteStatus>
{loading ? "Loading..." : null}
</AutocompleteStatus>
<AutocompleteEmpty>No results found.</AutocompleteEmpty>
<AutocompleteList>
{(fruit: Fruit) => (
<AutocompleteItem key={fruit.id} value={fruit}>
{fruit.value}
</AutocompleteItem>
)}
</AutocompleteList>
</AutocompleteContent>
</Autocomplete>
);
}
Limit Results
import { useFilter } from "@/components/ui/autocomplete";
function LimitedAutocomplete() {
const filter = useFilter();
const maxResults = 5;
return (
<Autocomplete items={fruits} filter={filter}>
<AutocompleteInput placeholder="Type to search..." />
<AutocompleteContent>
<AutocompleteEmpty>No results found.</AutocompleteEmpty>
<AutocompleteList>
{(fruit: Fruit, index: number) =>
index < maxResults ? (
<AutocompleteItem key={fruit.id} value={fruit}>
{fruit.value}
</AutocompleteItem>
) : null
}
</AutocompleteList>
</AutocompleteContent>
</Autocomplete>
);
}
With Custom Filtering
import { useFilter } from "@/components/ui/autocomplete";
function CustomFilterAutocomplete() {
const customFilter = useFilter({
matchOption: (option, query) => {
// Custom fuzzy matching logic
return option.value.toLowerCase().includes(query.toLowerCase());
},
});
return (
<Autocomplete items={fruits} filter={customFilter}>
<AutocompleteInput placeholder="Type to search..." />
<AutocompleteContent>
<AutocompleteList>
{(fruit: Fruit) => (
<AutocompleteItem key={fruit.id} value={fruit}>
{fruit.value}
</AutocompleteItem>
)}
</AutocompleteList>
</AutocompleteContent>
</Autocomplete>
);
}
API Reference
Autocomplete
Extends all props from @base-ui/react Autocomplete.Root component.
Array of items for suggestions.
The controlled selected value.
The default selected value when uncontrolled.
Callback fired when the selected value changes.
Controlled open state of the popup.
Callback when popup open state changes.
Whether to open the popup when clicking the input.
Whether the autocomplete is disabled.
Custom filter function for items. Use useFilter hook.
AutocompleteInput
Placeholder text for the input.
Callback when input value changes.
Custom render element. Defaults to Input component.
Additional CSS classes to apply.
AutocompleteContent
Distance in pixels from the input.
Additional CSS classes to apply.
AutocompleteItem
The value of the suggestion item.
Whether the item is disabled.
Additional CSS classes to apply.
AutocompleteList
Container for autocomplete items with scroll support.
AutocompleteEmpty
Displayed when no items match the input.
AutocompleteStatus
Displays status messages (e.g., loading state).
useFilter
Hook for creating custom filter functions.
const filter = useFilter({
matchOption: (option, query) => boolean,
});
TypeScript
import { Autocomplete as AutocompletePrimitive } from "@base-ui/react";
const Autocomplete = AutocompletePrimitive.Root;
const useFilter = AutocompletePrimitive.useFilter;
type AutocompleteInputProps = React.ComponentProps<typeof AutocompletePrimitive.Input>;
type AutocompleteItemProps = React.ComponentProps<typeof AutocompletePrimitive.Item>;
Accessibility
- Keyboard navigation (Arrow keys, Enter, Escape)
- Proper ARIA attributes
- Screen reader announcements
- Focus management
- Type-ahead support
Related
- Combobox - Similar with selection focus
- Input - Basic text input
- Select - Dropdown without search