Components
Autocomplete
An input that suggests options as you type.
Loading...
Installation
CLI
npx shadcn@latest add https://exawizards.com/exabase/design/registry/autocomplete.jsonManual
Copy and paste the following code into your project.
// Based on coss ui (https://github.com/cosscom/coss/blob/main/apps/ui/registry/default/ui/autocomplete.tsx)
// Copyright (c) coss.com - MIT License
"use client"
import { Autocomplete as AutocompletePrimitive } from "@base-ui/react/autocomplete"
import { XmarkLargeIcon } from "@exawizards/exabase-design-system-icons-react"
import { cn } from "@/lib/utils"
import { Input } from "@/components/ui/input"
import { ScrollArea } from "@/components/ui/scroll-area"
const Autocomplete = AutocompletePrimitive.Root
function AutocompleteInput({
className,
size,
render,
...props
}: Omit<AutocompletePrimitive.Input.Props, "size"> &
React.ComponentProps<typeof Input>) {
return (
<AutocompletePrimitive.Input
className={cn(className)}
data-slot="autocomplete-input"
render={render ?? <Input size={size} />}
{...props}
/>
)
}
function AutocompleteContent({
className,
children,
side = "bottom",
sideOffset = 4,
alignOffset,
align = "start",
anchor,
...props
}: AutocompletePrimitive.Popup.Props & {
align?: AutocompletePrimitive.Positioner.Props["align"]
sideOffset?: AutocompletePrimitive.Positioner.Props["sideOffset"]
alignOffset?: AutocompletePrimitive.Positioner.Props["alignOffset"]
side?: AutocompletePrimitive.Positioner.Props["side"]
anchor?: AutocompletePrimitive.Positioner.Props["anchor"]
}) {
return (
<AutocompletePrimitive.Portal>
<AutocompletePrimitive.Positioner
align={align}
alignOffset={alignOffset}
anchor={anchor}
className="z-50 select-none"
side={side}
sideOffset={sideOffset}
>
<AutocompletePrimitive.Popup
className={cn(
"relative isolate z-50 max-h-(--available-height) min-w-[var(--anchor-width)] origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-lg bg-popover text-popover-foreground shadow-md outline outline-border",
className
)}
data-slot="autocomplete-content"
{...props}
>
{children}
</AutocompletePrimitive.Popup>
</AutocompletePrimitive.Positioner>
</AutocompletePrimitive.Portal>
)
}
function AutocompleteItem({
className,
children,
...props
}: AutocompletePrimitive.Item.Props) {
return (
<AutocompletePrimitive.Item
className={cn(
"flex w-full cursor-default items-center gap-1.5 rounded-md px-1.5 py-1 text-sm select-none focus:outline-hidden data-highlighted:bg-accent data-highlighted:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
className
)}
data-slot="autocomplete-item"
{...props}
>
{children}
</AutocompletePrimitive.Item>
)
}
function AutocompleteSeparator({
className,
...props
}: AutocompletePrimitive.Separator.Props) {
return (
<AutocompletePrimitive.Separator
data-slot="autocomplete-separator"
className={cn("m-1 border-b", className)}
{...props}
/>
)
}
function AutocompleteGroup({ ...props }: AutocompletePrimitive.Group.Props) {
return (
<AutocompletePrimitive.Group data-slot="autocomplete-group" {...props} />
)
}
function AutocompleteLabel({
className,
...props
}: AutocompletePrimitive.GroupLabel.Props) {
return (
<AutocompletePrimitive.GroupLabel
className={cn(
"px-1.5 py-1 text-xs font-medium text-muted-foreground",
className
)}
data-slot="autocomplete-label"
{...props}
/>
)
}
function AutocompleteEmpty({
className,
...props
}: AutocompletePrimitive.Empty.Props) {
return (
<AutocompletePrimitive.Empty
className={cn(
"p-2 text-center text-sm text-muted-foreground empty:m-0 empty:p-0",
className
)}
data-slot="autocomplete-empty"
{...props}
/>
)
}
function AutocompleteRow({ ...props }: AutocompletePrimitive.Row.Props) {
return <AutocompletePrimitive.Row data-slot="autocomplete-row" {...props} />
}
function AutocompleteValue({ ...props }: AutocompletePrimitive.Value.Props) {
return (
<AutocompletePrimitive.Value data-slot="autocomplete-value" {...props} />
)
}
function AutocompleteList({
className,
...props
}: AutocompletePrimitive.List.Props) {
return (
<ScrollArea>
<AutocompletePrimitive.List
className={cn(
"not-empty:scroll-py-1 not-empty:p-1 in-data-has-overflow-y:pe-3",
className
)}
data-slot="autocomplete-list"
{...props}
/>
</ScrollArea>
)
}
function AutocompleteClear({
className,
...props
}: AutocompletePrimitive.Clear.Props) {
return (
<AutocompletePrimitive.Clear
className={cn(
"absolute end-0.5 top-1/2 inline-flex size-8 shrink-0 -translate-y-1/2 cursor-pointer items-center justify-center rounded-md border border-transparent opacity-80 transition-[color,background-color,box-shadow,opacity] outline-none hover:opacity-100 sm:size-7 pointer-coarse:after:absolute pointer-coarse:after:min-h-11 pointer-coarse:after:min-w-11 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4",
className
)}
data-slot="autocomplete-clear"
{...props}
>
<XmarkLargeIcon />
</AutocompletePrimitive.Clear>
)
}
function AutocompleteStatus({
className,
...props
}: AutocompletePrimitive.Status.Props) {
return (
<AutocompletePrimitive.Status
className={cn(
"px-3 py-2 text-xs font-medium text-muted-foreground empty:m-0 empty:p-0",
className
)}
data-slot="autocomplete-status"
{...props}
/>
)
}
function AutocompleteCollection({
...props
}: AutocompletePrimitive.Collection.Props) {
return (
<AutocompletePrimitive.Collection
data-slot="autocomplete-collection"
{...props}
/>
)
}
function AutocompleteTrigger({
className,
children,
...props
}: AutocompletePrimitive.Trigger.Props) {
return (
<AutocompletePrimitive.Trigger
className={className}
data-slot="autocomplete-trigger"
{...props}
>
{children}
</AutocompletePrimitive.Trigger>
)
}
const useAutocompleteFilter = AutocompletePrimitive.useFilter
export {
Autocomplete,
AutocompleteInput,
AutocompleteTrigger,
AutocompleteContent,
AutocompleteItem,
AutocompleteSeparator,
AutocompleteGroup,
AutocompleteLabel,
AutocompleteEmpty,
AutocompleteValue,
AutocompleteList,
AutocompleteClear,
AutocompleteStatus,
AutocompleteRow,
AutocompleteCollection,
useAutocompleteFilter,
}
Usage
import {
Autocomplete,
AutocompleteEmpty,
AutocompleteInput,
AutocompleteItem,
AutocompleteList,
AutocompleteContent,
} 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..." />
<AutocompleteContent>
<AutocompleteEmpty>No results found.</AutocompleteEmpty>
<AutocompleteList>
{(item) => <AutocompleteItem key={item.value} value={item}>{item.label}</AutocompleteItem>}
</AutocompleteList>
</AutocompleteContent>
</Autocomplete>Examples
Size
Loading...
Grouped
Loading...
Disabled
Loading...
Inline Autocomplete
Autofill the input with the highlighted item while navigating with arrow keys using the mode prop. Accepts aria-autocomplete values list, both, inline, or none.
Loading...
Auto Highlight
Automatically highlight the first matching item.
Loading...
Input Group
Loading...
Limit Results
Loading...
API
See the Base UI documentation for more information.
AutocompleteInput
| Prop | Type | Default | Description |
|---|---|---|---|
size | "xs" | "sm" | "default" | number | "default" | When xs, sm, or default is specified, the size variant is applied. When a number is specified, it is reflected in the native input's size attribute. |