Components
- Accordion
- Alert
- Alert Dialog
- Autocomplete
- Avatar
- Badge
- Breadcrumb
- Button
- Card
- Checkbox
- Checkbox Group
- Collapsible
- Combobox
- Dialog
- EmptyNew
- Field
- Fieldset
- Form
- Frame
- Group
- Input
- Input GroupNew
- KbdNew
- Label
- Menu
- Meter
- Number Field
- Pagination
- Popover
- Preview Card
- Progress
- Radio Group
- Scroll Area
- Select
- Separator
- Sheet
- SkeletonNew
- Slider
- SpinnerNew
- Switch
- Table
- Tabs
- Textarea
- Toast
- Toggle
- Toggle Group
- Toolbar
- Tooltip
Resources
Autocomplete
An input that suggests options as you type.
"use client";
import {
Autocomplete,
AutocompleteEmpty,
AutocompleteInput,
AutocompleteItem,
AutocompleteList,
AutocompletePopup,
} from "@/components/ui/autocomplete";
const items = [
{ label: "Apple", value: "apple" },
{ label: "Banana", value: "banana" },
{ label: "Orange", value: "orange" },
{ label: "Grape", value: "grape" },
{ label: "Strawberry", value: "strawberry" },
{ label: "Mango", value: "mango" },
{ label: "Pineapple", value: "pineapple" },
{ label: "Kiwi", value: "kiwi" },
{ label: "Peach", value: "peach" },
{ label: "Pear", value: "pear" },
];
export default function Particle() {
return (
<Autocomplete items={items}>
<AutocompleteInput
aria-label="Search items"
placeholder="Search items…"
/>
<AutocompletePopup>
<AutocompleteEmpty>No items found.</AutocompleteEmpty>
<AutocompleteList>
{(item) => (
<AutocompleteItem key={item.value} value={item}>
{item.label}
</AutocompleteItem>
)}
</AutocompleteList>
</AutocompletePopup>
</Autocomplete>
);
}
Installation
pnpm dlx shadcn@latest add @coss/autocomplete
Usage
import {
Autocomplete,
AutocompleteEmpty,
AutocompleteInput,
AutocompleteItem,
AutocompleteList,
AutocompletePopup,
} from "@/components/ui/autocomplete"const items = [
{ value: "apple", label: "Apple" },
{ value: "banana", label: "Banana" },
{ value: "orange", label: "Orange" },
{ value: "grape", label: "Grape" },
]
<Autocomplete items={items}>
<AutocompleteInput placeholder="Search..." />
<AutocompletePopup>
<AutocompleteEmpty>No results found.</AutocompleteEmpty>
<AutocompleteList>
{(item) => <AutocompleteItem key={item.value} value={item}>{item.label}</AutocompleteItem>}
</AutocompleteList>
</AutocompletePopup>
</Autocomplete>API Reference
The AutocompleteInput component extends the original Base UI component with a few extra props:
| Prop | Type | Default | Description |
|---|---|---|---|
size | "sm" | "default" | "lg" | "default" | The size variant of the input field. |
showTrigger | boolean | false | Whether to display a trigger button (chevron icon) on the right side of the input. |
showClear | boolean | false | Whether to display a clear button (X icon) on the right side of the input when there is a value. |
Examples
Disabled
"use client";
import {
Autocomplete,
AutocompleteEmpty,
AutocompleteInput,
AutocompleteItem,
AutocompleteList,
AutocompletePopup,
} from "@/components/ui/autocomplete";
const items = [
{ label: "Apple", value: "apple" },
{ label: "Banana", value: "banana" },
{ label: "Orange", value: "orange" },
{ label: "Grape", value: "grape" },
{ label: "Strawberry", value: "strawberry" },
{ label: "Mango", value: "mango" },
{ label: "Pineapple", value: "pineapple" },
{ label: "Kiwi", value: "kiwi" },
{ label: "Peach", value: "peach" },
{ label: "Pear", value: "pear" },
];
export default function Particle() {
return (
<Autocomplete disabled items={items}>
<AutocompleteInput
aria-label="Search items"
placeholder="Search items…"
/>
<AutocompletePopup>
<AutocompleteEmpty>No items found.</AutocompleteEmpty>
<AutocompleteList>
{(item) => (
<AutocompleteItem key={item.value} value={item}>
{item.label}
</AutocompleteItem>
)}
</AutocompleteList>
</AutocompletePopup>
</Autocomplete>
);
}
Small Size
"use client";
import {
Autocomplete,
AutocompleteEmpty,
AutocompleteInput,
AutocompleteItem,
AutocompleteList,
AutocompletePopup,
} from "@/components/ui/autocomplete";
const items = [
{ label: "Apple", value: "apple" },
{ label: "Banana", value: "banana" },
{ label: "Orange", value: "orange" },
{ label: "Grape", value: "grape" },
{ label: "Strawberry", value: "strawberry" },
{ label: "Mango", value: "mango" },
{ label: "Pineapple", value: "pineapple" },
{ label: "Kiwi", value: "kiwi" },
{ label: "Peach", value: "peach" },
{ label: "Pear", value: "pear" },
];
export default function Particle() {
return (
<Autocomplete items={items}>
<AutocompleteInput
aria-label="Search items"
placeholder="Search items…"
size="sm"
/>
<AutocompletePopup>
<AutocompleteEmpty>No items found.</AutocompleteEmpty>
<AutocompleteList>
{(item) => (
<AutocompleteItem key={item.value} value={item}>
{item.label}
</AutocompleteItem>
)}
</AutocompleteList>
</AutocompletePopup>
</Autocomplete>
);
}
Large Size
"use client";
import {
Autocomplete,
AutocompleteEmpty,
AutocompleteInput,
AutocompleteItem,
AutocompleteList,
AutocompletePopup,
} from "@/components/ui/autocomplete";
const items = [
{ label: "Apple", value: "apple" },
{ label: "Banana", value: "banana" },
{ label: "Orange", value: "orange" },
{ label: "Grape", value: "grape" },
{ label: "Strawberry", value: "strawberry" },
{ label: "Mango", value: "mango" },
{ label: "Pineapple", value: "pineapple" },
{ label: "Kiwi", value: "kiwi" },
{ label: "Peach", value: "peach" },
{ label: "Pear", value: "pear" },
];
export default function Particle() {
return (
<Autocomplete items={items}>
<AutocompleteInput
aria-label="Search items"
placeholder="Search items…"
size="lg"
/>
<AutocompletePopup>
<AutocompleteEmpty>No items found.</AutocompleteEmpty>
<AutocompleteList>
{(item) => (
<AutocompleteItem key={item.value} value={item}>
{item.label}
</AutocompleteItem>
)}
</AutocompleteList>
</AutocompletePopup>
</Autocomplete>
);
}
With Label
"use client";
import { useId } from "react";
import {
Autocomplete,
AutocompleteEmpty,
AutocompleteInput,
AutocompleteItem,
AutocompleteList,
AutocompletePopup,
} from "@/components/ui/autocomplete";
import { Label } from "@/components/ui/label";
const items = [
{ label: "Apple", value: "apple" },
{ label: "Banana", value: "banana" },
{ label: "Orange", value: "orange" },
{ label: "Grape", value: "grape" },
{ label: "Strawberry", value: "strawberry" },
{ label: "Mango", value: "mango" },
{ label: "Pineapple", value: "pineapple" },
{ label: "Kiwi", value: "kiwi" },
{ label: "Peach", value: "peach" },
{ label: "Pear", value: "pear" },
];
export default function Particle() {
const id = useId();
return (
<Autocomplete items={items}>
<div className="flex flex-col items-start gap-2">
<Label htmlFor={id}>Fruits</Label>
<AutocompleteInput
aria-label="Search items"
id={id}
placeholder="Search items…"
/>
</div>
<AutocompletePopup>
<AutocompleteEmpty>No items found.</AutocompleteEmpty>
<AutocompleteList>
{(item) => (
<AutocompleteItem key={item.value} value={item}>
{item.label}
</AutocompleteItem>
)}
</AutocompleteList>
</AutocompletePopup>
</Autocomplete>
);
}
Inline Autocomplete
Autofill the input with the highlighted item while navigating with arrow keys.
"use client";
import {
Autocomplete,
AutocompleteEmpty,
AutocompleteInput,
AutocompleteItem,
AutocompleteList,
AutocompletePopup,
} from "@/components/ui/autocomplete";
const items = [
{ label: "Apple", value: "apple" },
{ label: "Banana", value: "banana" },
{ label: "Orange", value: "orange" },
{ label: "Grape", value: "grape" },
{ label: "Strawberry", value: "strawberry" },
{ label: "Mango", value: "mango" },
{ label: "Pineapple", value: "pineapple" },
{ label: "Kiwi", value: "kiwi" },
{ label: "Peach", value: "peach" },
{ label: "Pear", value: "pear" },
];
export default function Particle() {
return (
<Autocomplete items={items} mode="both">
<AutocompleteInput
aria-label="Search items"
placeholder="Search items…"
/>
<AutocompletePopup>
<AutocompleteEmpty>No items found.</AutocompleteEmpty>
<AutocompleteList>
{(item) => (
<AutocompleteItem key={item.value} value={item}>
{item.label}
</AutocompleteItem>
)}
</AutocompleteList>
</AutocompletePopup>
</Autocomplete>
);
}
Auto Highlight
Automatically highlight the first matching option.
"use client";
import {
Autocomplete,
AutocompleteEmpty,
AutocompleteInput,
AutocompleteItem,
AutocompleteList,
AutocompletePopup,
} from "@/components/ui/autocomplete";
const items = [
{ label: "Apple", value: "apple" },
{ label: "Banana", value: "banana" },
{ label: "Orange", value: "orange" },
{ label: "Grape", value: "grape" },
{ label: "Strawberry", value: "strawberry" },
{ label: "Mango", value: "mango" },
{ label: "Pineapple", value: "pineapple" },
{ label: "Kiwi", value: "kiwi" },
{ label: "Peach", value: "peach" },
{ label: "Pear", value: "pear" },
];
export default function Particle() {
return (
<Autocomplete autoHighlight items={items}>
<AutocompleteInput
aria-label="Search items"
placeholder="Search items…"
/>
<AutocompletePopup>
<AutocompleteEmpty>No items found.</AutocompleteEmpty>
<AutocompleteList>
{(item) => (
<AutocompleteItem key={item.value} value={item}>
{item.label}
</AutocompleteItem>
)}
</AutocompleteList>
</AutocompletePopup>
</Autocomplete>
);
}
With Clear Button
"use client";
import {
Autocomplete,
AutocompleteEmpty,
AutocompleteInput,
AutocompleteItem,
AutocompleteList,
AutocompletePopup,
} from "@/components/ui/autocomplete";
const items = [
{ label: "Apple", value: "apple" },
{ label: "Banana", value: "banana" },
{ label: "Orange", value: "orange" },
{ label: "Grape", value: "grape" },
{ label: "Strawberry", value: "strawberry" },
{ label: "Mango", value: "mango" },
{ label: "Pineapple", value: "pineapple" },
{ label: "Kiwi", value: "kiwi" },
{ label: "Peach", value: "peach" },
{ label: "Pear", value: "pear" },
];
export default function Particle() {
return (
<Autocomplete items={items}>
<AutocompleteInput
aria-label="Search items"
placeholder="Search items…"
showClear
/>
<AutocompletePopup>
<AutocompleteEmpty>No items found.</AutocompleteEmpty>
<AutocompleteList>
{(item) => (
<AutocompleteItem key={item.value} value={item}>
{item.label}
</AutocompleteItem>
)}
</AutocompleteList>
</AutocompletePopup>
</Autocomplete>
);
}
With Trigger and Clear Buttons
"use client";
import {
Autocomplete,
AutocompleteEmpty,
AutocompleteInput,
AutocompleteItem,
AutocompleteList,
AutocompletePopup,
} from "@/components/ui/autocomplete";
const items = [
{ label: "Apple", value: "apple" },
{ label: "Banana", value: "banana" },
{ label: "Orange", value: "orange" },
{ label: "Grape", value: "grape" },
{ label: "Strawberry", value: "strawberry" },
{ label: "Mango", value: "mango" },
{ label: "Pineapple", value: "pineapple" },
{ label: "Kiwi", value: "kiwi" },
{ label: "Peach", value: "peach" },
{ label: "Pear", value: "pear" },
];
export default function Particle() {
return (
<Autocomplete items={items}>
<AutocompleteInput
aria-label="Search items"
placeholder="Search items…"
showClear
showTrigger
/>
<AutocompletePopup>
<AutocompleteEmpty>No items found.</AutocompleteEmpty>
<AutocompleteList>
{(item) => (
<AutocompleteItem key={item.value} value={item}>
{item.label}
</AutocompleteItem>
)}
</AutocompleteList>
</AutocompletePopup>
</Autocomplete>
);
}
With Groups
"use client";
import * as React from "react";
import {
Autocomplete,
AutocompleteCollection,
AutocompleteEmpty,
AutocompleteGroup,
AutocompleteGroupLabel,
AutocompleteInput,
AutocompleteItem,
AutocompleteList,
AutocompletePopup,
AutocompleteSeparator,
} from "@/components/ui/autocomplete";
// Grouped items demo
type Tag = { id: string; label: string; group: "Status" | "Priority" | "Team" };
type TagGroup = { value: string; items: Tag[] };
const tagsData: Tag[] = [
// Status
{ group: "Status", id: "s-open", label: "Open" },
{ group: "Status", id: "s-in-progress", label: "In progress" },
{ group: "Status", id: "s-blocked", label: "Blocked" },
{ group: "Status", id: "s-resolved", label: "Resolved" },
{ group: "Status", id: "s-closed", label: "Closed" },
// Priority
{ group: "Priority", id: "p-low", label: "Low" },
{ group: "Priority", id: "p-medium", label: "Medium" },
{ group: "Priority", id: "p-high", label: "High" },
{ group: "Priority", id: "p-urgent", label: "Urgent" },
// Team
{ group: "Team", id: "t-design", label: "Design" },
{ group: "Team", id: "t-frontend", label: "Frontend" },
{ group: "Team", id: "t-backend", label: "Backend" },
{ group: "Team", id: "t-devops", label: "DevOps" },
{ group: "Team", id: "t-qa", label: "QA" },
{ group: "Team", id: "t-mobile", label: "Mobile" },
{ group: "Team", id: "t-data", label: "Data" },
{ group: "Team", id: "t-security", label: "Security" },
{ group: "Team", id: "t-platform", label: "Platform" },
{ group: "Team", id: "t-infra", label: "Infrastructure" },
{ group: "Team", id: "t-product", label: "Product" },
{ group: "Team", id: "t-marketing", label: "Marketing" },
{ group: "Team", id: "t-sales", label: "Sales" },
{ group: "Team", id: "t-support", label: "Support" },
{ group: "Team", id: "t-research", label: "Research" },
{ group: "Team", id: "t-content", label: "Content" },
{ group: "Team", id: "t-analytics", label: "Analytics" },
{ group: "Team", id: "t-operations", label: "Operations" },
{ group: "Team", id: "t-finance", label: "Finance" },
{ group: "Team", id: "t-hr", label: "HR" },
{ group: "Team", id: "t-legal", label: "Legal" },
{ group: "Team", id: "t-growth", label: "Growth" },
{ group: "Team", id: "t-partner", label: "Partner" },
{ group: "Team", id: "t-community", label: "Community" },
{ group: "Team", id: "t-docs", label: "Docs" },
{ group: "Team", id: "t-l10n", label: "Localization" },
{ group: "Team", id: "t-a11y", label: "Accessibility" },
{ group: "Team", id: "t-sre", label: "SRE" },
{ group: "Team", id: "t-release", label: "Release" },
{ group: "Team", id: "t-architecture", label: "Architecture" },
{ group: "Team", id: "t-ux", label: "UX" },
{ group: "Team", id: "t-ui", label: "UI" },
{ group: "Team", id: "t-management", label: "Management" },
];
function groupTags(tags: Tag[]): TagGroup[] {
const groups: Record<string, Tag[]> = {};
for (const tag of tags) {
if (!groups[tag.group]) {
groups[tag.group] = [];
}
// biome-ignore lint/style/noNonNullAssertion: will never be null
groups[tag.group]!.push(tag);
}
const order: Array<TagGroup["value"]> = ["Status", "Priority", "Team"];
return order.map((value) => ({ items: groups[value] ?? [], value }));
}
const groupedTags: TagGroup[] = groupTags(tagsData);
export default function Particle() {
return (
<Autocomplete items={groupedTags}>
<div className="flex flex-col items-start gap-2">
<AutocompleteInput
aria-label="Search tags"
placeholder="e.g. feature"
/>
</div>
<AutocompletePopup>
<AutocompleteEmpty>No tags found.</AutocompleteEmpty>
<AutocompleteList>
{(group: TagGroup) => (
<React.Fragment key={group.value}>
<AutocompleteGroup items={group.items}>
<AutocompleteGroupLabel>{group.value}</AutocompleteGroupLabel>
<AutocompleteCollection>
{(tag: Tag) => (
<AutocompleteItem key={tag.id} value={tag}>
{tag.label}
</AutocompleteItem>
)}
</AutocompleteCollection>
</AutocompleteGroup>
{group.value !== "Team" && <AutocompleteSeparator />}
</React.Fragment>
)}
</AutocompleteList>
</AutocompletePopup>
</Autocomplete>
);
}
With Limit Results
"use client";
import { Autocomplete as AutocompletePrimitive } from "@base-ui-components/react/autocomplete";
import * as React from "react";
import {
Autocomplete,
AutocompleteEmpty,
AutocompleteInput,
AutocompleteItem,
AutocompleteList,
AutocompletePopup,
AutocompleteStatus,
} from "@/components/ui/autocomplete";
// Limit results demo
const limit = 7;
type SimpleTag = { id: string; value: string };
const manyTags: SimpleTag[] = [
{ id: "lang-js", value: "JavaScript" },
{ id: "lang-ts", value: "TypeScript" },
{ id: "lang-py", value: "Python" },
{ id: "lang-java", value: "Java" },
{ id: "lang-csharp", value: "C#" },
{ id: "lang-cpp", value: "C++" },
{ id: "lang-c", value: "C" },
{ id: "lang-go", value: "Go" },
{ id: "lang-rust", value: "Rust" },
{ id: "lang-rb", value: "Ruby" },
{ id: "lang-php", value: "PHP" },
{ id: "lang-swift", value: "Swift" },
{ id: "lang-kotlin", value: "Kotlin" },
{ id: "lang-scala", value: "Scala" },
{ id: "lang-elixir", value: "Elixir" },
{ id: "lang-hs", value: "Haskell" },
{ id: "lang-dart", value: "Dart" },
{ id: "lang-objc", value: "Objective-C" },
{ id: "lang-julia", value: "Julia" },
{ id: "lang-r", value: "R" },
{ id: "lang-perl", value: "Perl" },
{ id: "lang-lua", value: "Lua" },
{ id: "lang-ocaml", value: "OCaml" },
{ id: "lang-fsharp", value: "F#" },
];
export default function Particle() {
const [value, setValue] = React.useState("");
const { contains } = AutocompletePrimitive.useFilter({ sensitivity: "base" });
const totalMatches = React.useMemo(() => {
const trimmed = value.trim();
if (!trimmed) return manyTags.length;
return manyTags.filter((t) => contains(t.value, trimmed)).length;
}, [value, contains]);
const moreCount = Math.max(0, totalMatches - limit);
return (
<Autocomplete
items={manyTags}
limit={limit}
onValueChange={setValue}
value={value}
>
<AutocompleteInput placeholder="e.g. feature" />
<AutocompletePopup>
<AutocompleteEmpty>No tags found.</AutocompleteEmpty>
<AutocompleteList>
{(tag: SimpleTag) => (
<AutocompleteItem key={tag.id} value={tag}>
{tag.value}
</AutocompleteItem>
)}
</AutocompleteList>
{moreCount > 0 && (
<AutocompleteStatus>
+{moreCount} more (keep typing to narrow down)
</AutocompleteStatus>
)}
</AutocompletePopup>
</Autocomplete>
);
}
Async Search
"use client";
import { Autocomplete as AutocompletePrimitive } from "@base-ui-components/react/autocomplete";
import * as React from "react";
import {
Autocomplete,
AutocompleteInput,
AutocompleteItem,
AutocompleteList,
AutocompletePopup,
AutocompleteStatus,
} from "@/components/ui/autocomplete";
import { Spinner } from "@/components/ui/spinner";
type Movie = { id: string; title: string; year: number };
const top100Movies: Movie[] = [
{ id: "1", title: "The Shawshank Redemption", year: 1994 },
{ id: "2", title: "The Godfather", year: 1972 },
{ id: "3", title: "The Dark Knight", year: 2008 },
{ id: "4", title: "The Godfather Part II", year: 1974 },
{ id: "5", title: "12 Angry Men", year: 1957 },
{ id: "8", title: "Pulp Fiction", year: 1994 },
{ id: "11", title: "Forrest Gump", year: 1994 },
{ id: "14", title: "Inception", year: 2010 },
];
async function searchMovies(
query: string,
filter: (item: string, query: string) => boolean,
): Promise<Movie[]> {
await new Promise((resolve) =>
setTimeout(resolve, Math.random() * 500 + 100),
);
if (Math.random() < 0.01 || query === "will_error") {
throw new Error("Network error");
}
return top100Movies.filter(
(movie) =>
filter(movie.title, query) || filter(movie.year.toString(), query),
);
}
export default function Particle() {
const [searchValue, setSearchValue] = React.useState("");
const [isLoading, setIsLoading] = React.useState(false);
const [searchResults, setSearchResults] = React.useState<Movie[]>([]);
const [error, setError] = React.useState<string | null>(null);
const { contains } = AutocompletePrimitive.useFilter({ sensitivity: "base" });
React.useEffect(() => {
if (!searchValue) {
setSearchResults([]);
setIsLoading(false);
return;
}
setIsLoading(true);
setError(null);
let ignore = false;
const timeoutId = setTimeout(async () => {
try {
const results = await searchMovies(searchValue, contains);
if (!ignore) setSearchResults(results);
} catch {
if (!ignore) {
setError("Failed to fetch movies. Please try again.");
setSearchResults([]);
}
} finally {
if (!ignore) setIsLoading(false);
}
}, 300);
return () => {
clearTimeout(timeoutId);
ignore = true;
};
}, [searchValue, contains]);
let status: React.ReactNode = `${searchResults.length} result${searchResults.length === 1 ? "" : "s"} found`;
if (isLoading) {
status = (
<span className="flex items-center justify-between gap-2 text-muted-foreground">
Searching...
<Spinner />
</span>
);
} else if (error) {
status = (
<span className="font-normal text-destructive text-sm">{error}</span>
);
} else if (searchResults.length === 0 && searchValue) {
status = (
<span className="font-normal text-muted-foreground text-sm">
Movie or year "{searchValue}" does not exist in the Top 100 IMDb movies
</span>
);
}
const shouldRenderPopup = searchValue !== "";
return (
<Autocomplete
filter={null}
items={searchResults}
itemToStringValue={(item: unknown) => (item as Movie).title}
onValueChange={setSearchValue}
value={searchValue}
>
<AutocompleteInput placeholder="e.g. Pulp Fiction or 1994" />
{shouldRenderPopup && (
<AutocompletePopup aria-busy={isLoading || undefined}>
<AutocompleteStatus className="text-muted-foreground">
{status}
</AutocompleteStatus>
<AutocompleteList>
{(movie: Movie) => (
<AutocompleteItem key={movie.id} value={movie}>
<div className="flex w-full flex-col gap-1">
<div className="font-medium">{movie.title}</div>
<div className="text-muted-foreground text-xs">
{movie.year}
</div>
</div>
</AutocompleteItem>
)}
</AutocompleteList>
</AutocompletePopup>
)}
</Autocomplete>
);
}
Form Integration
"use client";
import * as React from "react";
import {
Autocomplete,
AutocompleteEmpty,
AutocompleteInput,
AutocompleteItem,
AutocompleteList,
AutocompletePopup,
} from "@/components/ui/autocomplete";
import { Button } from "@/components/ui/button";
import { Field, FieldError, FieldLabel } from "@/components/ui/field";
import { Form } from "@/components/ui/form";
const items = [
{ label: "Apple", value: "apple" },
{ label: "Banana", value: "banana" },
{ label: "Orange", value: "orange" },
{ label: "Grape", value: "grape" },
{ label: "Strawberry", value: "strawberry" },
{ label: "Mango", value: "mango" },
{ label: "Pineapple", value: "pineapple" },
{ label: "Kiwi", value: "kiwi" },
{ label: "Peach", value: "peach" },
{ label: "Pear", value: "pear" },
];
export default function Particle() {
const [loading, setLoading] = React.useState(false);
const onSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const formData = new FormData(e.currentTarget);
const selectedItem = formData.get("item");
// Base UI extracts the 'label' property from objects, so we need to find the corresponding value
const itemValue =
items.find((item) => item.label === selectedItem)?.value || selectedItem;
setLoading(true);
await new Promise((r) => setTimeout(r, 800));
setLoading(false);
alert(`Favorite item: ${itemValue || ""}`);
};
return (
<Form className="max-w-64" onSubmit={onSubmit}>
<Field>
<FieldLabel>Favorite item</FieldLabel>
<Autocomplete disabled={loading} items={items} name="item" required>
<AutocompleteInput placeholder="Search items…" />
<AutocompletePopup>
<AutocompleteEmpty>No items found.</AutocompleteEmpty>
<AutocompleteList>
{(item) => (
<AutocompleteItem key={item.value} value={item}>
{item.label}
</AutocompleteItem>
)}
</AutocompleteList>
</AutocompletePopup>
</Autocomplete>
<FieldError>Please select a item.</FieldError>
</Field>
<Button disabled={loading} type="submit">
Submit
</Button>
</Form>
);
}