Components
- Accordion
- Alert
- Alert Dialog
- Autocomplete
- Avatar
- Badge
- Breadcrumb
- Button
- Card
- Checkbox
- Checkbox Group
- Collapsible
- Combobox
- Dialog
- Field
- Fieldset
- Form
- Frame
- Group
- Input
- Label
- Menu
- Meter
- Number Field
- Pagination
- Popover
- Preview Card
- Progress
- Radio Group
- Scroll Area
- Select
- Separator
- Sheet
- Slider
- 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 function AutocompleteDemo() {
return (
<Autocomplete items={items}>
<AutocompleteInput
placeholder="Search items…"
aria-label="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 https://coss.com/ui/r/autocomplete.json
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 function AutocompleteDisabled() {
return (
<Autocomplete items={items} disabled>
<AutocompleteInput
placeholder="Search items…"
aria-label="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 function AutocompleteSm() {
return (
<Autocomplete items={items}>
<AutocompleteInput
size="sm"
placeholder="Search items…"
aria-label="Search items"
/>
<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 function AutocompleteLg() {
return (
<Autocomplete items={items}>
<AutocompleteInput
size="lg"
placeholder="Search items…"
aria-label="Search items"
/>
<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 function AutocompleteWithLabel() {
const id = useId()
return (
<Autocomplete items={items}>
<div className="flex flex-col items-start gap-2">
<Label htmlFor={id}>Fruits</Label>
<AutocompleteInput
id={id}
placeholder="Search items…"
aria-label="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 function AutocompleteInline() {
return (
<Autocomplete items={items} mode="both">
<AutocompleteInput
placeholder="Search items…"
aria-label="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 function AutocompleteAutohighlight() {
return (
<Autocomplete items={items} autoHighlight>
<AutocompleteInput
placeholder="Search items…"
aria-label="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 function AutocompleteWithClear() {
return (
<Autocomplete items={items}>
<AutocompleteInput
placeholder="Search items…"
aria-label="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 function AutocompleteWithTriggerClear() {
return (
<Autocomplete items={items}>
<AutocompleteInput
placeholder="Search items…"
aria-label="Search items"
showTrigger
showClear
/>
<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
{ 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", group: "Status" },
// 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", group: "Priority" },
// 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", group: "Team" },
]
function groupTags(tags: Tag[]): TagGroup[] {
const groups: Record<string, Tag[]> = {}
for (const t of tags) {
;(groups[t.group] ??= []).push(t)
}
const order: Array<TagGroup["value"]> = ["Status", "Priority", "Team"]
return order.map((value) => ({ value, items: groups[value] ?? [] }))
}
const groupedTags: TagGroup[] = groupTags(tagsData)
export function AutocompleteGrouped() {
return (
<Autocomplete items={groupedTags}>
<div className="flex flex-col items-start gap-2">
<AutocompleteInput
placeholder="e.g. feature"
aria-label="Search tags"
/>
</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 * as React from "react"
import { Autocomplete as AutocompletePrimitive } from "@base-ui-components/react/autocomplete"
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 function AutocompleteLimit() {
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}
value={value}
onValueChange={setValue}
limit={limit}
>
<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 * as React from "react"
import { Autocomplete as AutocompletePrimitive } from "@base-ui-components/react/autocomplete"
import { LoaderCircleIcon } from "lucide-react"
import {
Autocomplete,
AutocompleteInput,
AutocompleteItem,
AutocompleteList,
AutocompletePopup,
AutocompleteStatus,
} from "@/components/ui/autocomplete"
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 function AutocompleteAsync() {
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 (err) {
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...
<LoaderCircleIcon className="size-4 animate-spin" aria-hidden />
</span>
)
} else if (error) {
status = (
<span className="text-sm font-normal text-destructive">{error}</span>
)
} else if (searchResults.length === 0 && searchValue) {
status = (
<span className="text-sm font-normal text-muted-foreground">
Movie or year "{searchValue}" does not exist in the Top 100 IMDb movies
</span>
)
}
const shouldRenderPopup = searchValue !== ""
return (
<Autocomplete
items={searchResults}
value={searchValue}
onValueChange={setSearchValue}
itemToStringValue={(item: unknown) => (item as Movie).title}
filter={null}
>
<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 as any}>
<div className="flex w-full flex-col gap-1">
<div className="font-medium">{movie.title}</div>
<div className="text-xs text-muted-foreground">
{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 function AutocompleteForm() {
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 onSubmit={onSubmit} className="max-w-64">
<Field>
<FieldLabel>Favorite item</FieldLabel>
<Autocomplete items={items} name="item" disabled={loading} 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 type="submit" disabled={loading}>
Submit
</Button>
</Form>
)
}