Custom Shadcn Autocomplete for React and Tailwind CSS. An input that suggests options as you type.
Browse 12 production-ready Shadcn Autocomplete components for dashboards, forms, and product UI. These examples use Base UI primitives from @base-ui/react and stay fully compatible with Shadcn Create so radius, color, and typography match your configured theme.
Browse all 12 Shadcn Autocomplete components for copy-ready layouts, dashboards, and forms built with Tailwind CSS in the ReUI library.
import {
Autocomplete,
AutocompleteContent,
AutocompleteEmpty,
AutocompleteInput,
AutocompleteItem,
AutocompleteList,
} from "@/components/reui/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>import {
Autocomplete,
AutocompleteContent,
AutocompleteEmpty,
AutocompleteInput,
AutocompleteItem,
AutocompleteList,
} from "@/components/reui/autocomplete"
export function Pattern() {
return (
<div className="w-full max-w-xs">
<Autocomplete items={items}>
<AutocompleteInput placeholder="Search items" />
<AutocompleteContent>
<AutocompleteEmpty>No items found.</AutocompleteEmpty>
<AutocompleteList>
{(item) => (
<AutocompleteItem key={item.id} value={item.value}>
{item.value}
</AutocompleteItem>
)}
</AutocompleteList>
</AutocompleteContent>
</Autocomplete>
</div>
)
}
interface Item {
id: string
value: string
}
const items: Item[] = [
{ id: "t1", value: "Feature" },
{ id: "t2", value: "Fix" },
{ id: "t3", value: "Bug" },
{ id: "t4", value: "Docs" },
{ id: "t5", value: "Internal" },
{ id: "t6", value: "Mobile" },
{ id: "c-accordion", value: "component: Accordion" },
{ id: "c-alert-dialog", value: "component: Alert Dialog" },
{ id: "c-autocomplete", value: "component: Autocomplete" },
{ id: "c-avatar", value: "component: Avatar" },
{ id: "c-checkbox", value: "component: Checkbox" },
{ id: "c-checkbox-group", value: "component: Checkbox Group" },
{ id: "c-collapsible", value: "component: Collapsible" },
{ id: "c-combobox", value: "component: Combobox" },
{ id: "c-context-menu", value: "component: Context Menu" },
{ id: "c-dialog", value: "component: Dialog" },
{ id: "c-field", value: "component: Field" },
{ id: "c-fieldset", value: "component: Fieldset" },
{ id: "c-filterable-menu", value: "component: Filterable Menu" },
{ id: "c-form", value: "component: Form" },
{ id: "c-input", value: "component: Input" },
{ id: "c-menu", value: "component: Menu" },
{ id: "c-menubar", value: "component: Menubar" },
{ id: "c-meter", value: "component: Meter" },
{ id: "c-navigation-menu", value: "component: Navigation Menu" },
{ id: "c-number-field", value: "component: Number Field" },
{ id: "c-popover", value: "component: Popover" },
{ id: "c-preview-card", value: "component: Preview Card" },
{ id: "c-progress", value: "component: Progress" },
{ id: "c-radio", value: "component: Radio" },
{ id: "c-scroll-area", value: "component: Scroll Area" },
{ id: "c-select", value: "component: Select" },
{ id: "c-separator", value: "component: Separator" },
{ id: "c-slider", value: "component: Slider" },
{ id: "c-switch", value: "component: Switch" },
{ id: "c-tabs", value: "component: Tabs" },
{ id: "c-toast", value: "component: Toast" },
{ id: "c-toggle", value: "component: Toggle" },
{ id: "c-toggle-group", value: "component: Toggle Group" },
{ id: "c-toolbar", value: "component: Toolbar" },
{ id: "c-tooltip", value: "component: Tooltip" },
]
import {
Autocomplete,
AutocompleteContent,
AutocompleteEmpty,
AutocompleteInput,
AutocompleteItem,
AutocompleteList,
} from "@/components/reui/autocomplete"
import { Label } from "@/components/ui/label"
export function Pattern() {
return (
<div className="w-full max-w-xs">
<Autocomplete items={items} autoHighlight>
<div className="flex flex-col items-start gap-2">
<Label htmlFor="with-label">Label</Label>
<AutocompleteInput id="with-label" placeholder="e.g. feature" />
</div>
<AutocompleteContent>
<AutocompleteEmpty>No items found.</AutocompleteEmpty>
<AutocompleteList>
{(item) => (
<AutocompleteItem key={item.id} value={item.value}>
{item.value}
</AutocompleteItem>
)}
</AutocompleteList>
</AutocompleteContent>
</Autocomplete>
</div>
)
}
interface Item {
id: string
value: string
}
const items: Item[] = [
{ id: "t1", value: "feature" },
{ id: "t2", value: "fix" },
{ id: "t3", value: "bug" },
{ id: "t4", value: "docs" },
{ id: "t5", value: "internal" },
{ id: "t6", value: "mobile" },
{ id: "c-accordion", value: "component: accordion" },
{ id: "c-alert-dialog", value: "component: alert dialog" },
{ id: "c-autocomplete", value: "component: autocomplete" },
{ id: "c-avatar", value: "component: avatar" },
{ id: "c-checkbox", value: "component: checkbox" },
{ id: "c-checkbox-group", value: "component: checkbox group" },
{ id: "c-collapsible", value: "component: collapsible" },
{ id: "c-combobox", value: "component: combobox" },
{ id: "c-context-menu", value: "component: context menu" },
{ id: "c-dialog", value: "component: dialog" },
{ id: "c-field", value: "component: field" },
{ id: "c-fieldset", value: "component: fieldset" },
{ id: "c-filterable-menu", value: "component: filterable menu" },
{ id: "c-form", value: "component: form" },
{ id: "c-input", value: "component: input" },
{ id: "c-menu", value: "component: menu" },
{ id: "c-menubar", value: "component: menubar" },
{ id: "c-meter", value: "component: meter" },
{ id: "c-navigation-menu", value: "component: navigation menu" },
{ id: "c-number-field", value: "component: number field" },
{ id: "c-popover", value: "component: popover" },
{ id: "c-preview-card", value: "component: preview card" },
{ id: "c-progress", value: "component: progress" },
{ id: "c-radio", value: "component: radio" },
{ id: "c-scroll-area", value: "component: scroll area" },
{ id: "c-select", value: "component: select" },
{ id: "c-separator", value: "component: separator" },
{ id: "c-slider", value: "component: slider" },
{ id: "c-switch", value: "component: switch" },
{ id: "c-tabs", value: "component: tabs" },
{ id: "c-toast", value: "component: toast" },
{ id: "c-toggle", value: "component: toggle" },
{ id: "c-toggle-group", value: "component: toggle group" },
{ id: "c-toolbar", value: "component: toolbar" },
{ id: "c-tooltip", value: "component: tooltip" },
]
"use client"
import { useState } from "react"
import {
Autocomplete,
AutocompleteContent,
AutocompleteEmpty,
AutocompleteInput,
AutocompleteItem,
AutocompleteList,
} from "@/components/reui/autocomplete"
export function Pattern() {
const [value, setValue] = useState<string>("")
const filteredItems = items.filter((item) =>
item.value.toLowerCase().includes(value.toLowerCase())
)
return (
<div className="w-full max-w-xs">
<Autocomplete
value={value}
onValueChange={setValue}
items={filteredItems}
itemToStringValue={(item: unknown) => (item as Item).value}
>
<AutocompleteInput placeholder="e.g. feature" showClear />
<AutocompleteContent>
<AutocompleteEmpty>No items found.</AutocompleteEmpty>
<AutocompleteList>
{(item) => (
<AutocompleteItem key={item.id} value={item}>
{item.value}
</AutocompleteItem>
)}
</AutocompleteList>
</AutocompleteContent>
</Autocomplete>
</div>
)
}
interface Item {
id: string
value: string
}
const items: Item[] = [
{ id: "t1", value: "feature" },
{ id: "t2", value: "fix" },
{ id: "t3", value: "bug" },
{ id: "t4", value: "docs" },
{ id: "t5", value: "internal" },
{ id: "t6", value: "mobile" },
{ id: "c-accordion", value: "component: accordion" },
{ id: "c-alert-dialog", value: "component: alert dialog" },
{ id: "c-autocomplete", value: "component: autocomplete" },
{ id: "c-avatar", value: "component: avatar" },
{ id: "c-checkbox", value: "component: checkbox" },
{ id: "c-checkbox-group", value: "component: checkbox group" },
{ id: "c-collapsible", value: "component: collapsible" },
{ id: "c-combobox", value: "component: combobox" },
{ id: "c-context-menu", value: "component: context menu" },
{ id: "c-dialog", value: "component: dialog" },
{ id: "c-field", value: "component: field" },
{ id: "c-fieldset", value: "component: fieldset" },
{ id: "c-filterable-menu", value: "component: filterable menu" },
{ id: "c-form", value: "component: form" },
{ id: "c-input", value: "component: input" },
{ id: "c-menu", value: "component: menu" },
{ id: "c-menubar", value: "component: menubar" },
{ id: "c-meter", value: "component: meter" },
{ id: "c-navigation-menu", value: "component: navigation menu" },
{ id: "c-number-field", value: "component: number field" },
{ id: "c-popover", value: "component: popover" },
{ id: "c-preview-card", value: "component: preview card" },
{ id: "c-progress", value: "component: progress" },
{ id: "c-radio", value: "component: radio" },
{ id: "c-scroll-area", value: "component: scroll area" },
{ id: "c-select", value: "component: select" },
{ id: "c-separator", value: "component: separator" },
{ id: "c-slider", value: "component: slider" },
{ id: "c-switch", value: "component: switch" },
{ id: "c-tabs", value: "component: tabs" },
{ id: "c-toast", value: "component: toast" },
{ id: "c-toggle", value: "component: toggle" },
{ id: "c-toggle-group", value: "component: toggle group" },
{ id: "c-toolbar", value: "component: toolbar" },
{ id: "c-tooltip", value: "component: tooltip" },
]
"use client"
import { useState } from "react"
import {
Autocomplete,
AutocompleteContent,
AutocompleteEmpty,
AutocompleteInput,
AutocompleteItem,
AutocompleteList,
} from "@/components/reui/autocomplete"
export function Pattern() {
const [value, setValue] = useState<string>("")
const filteredItems = items.filter((item) =>
item.value.toLowerCase().includes(value.toLowerCase())
)
return (
<div className="w-full max-w-xs">
<Autocomplete
value={value}
onValueChange={setValue}
items={filteredItems}
itemToStringValue={(item: unknown) => (item as Item).value}
>
<AutocompleteInput placeholder="e.g. feature" showTrigger />
<AutocompleteContent>
<AutocompleteEmpty>No items found.</AutocompleteEmpty>
<AutocompleteList>
{(item) => (
<AutocompleteItem key={item.id} value={item}>
{item.value}
</AutocompleteItem>
)}
</AutocompleteList>
</AutocompleteContent>
</Autocomplete>
</div>
)
}
interface Item {
id: string
value: string
}
const items: Item[] = [
{ id: "t1", value: "feature" },
{ id: "t2", value: "fix" },
{ id: "t3", value: "bug" },
{ id: "t4", value: "docs" },
{ id: "t5", value: "internal" },
{ id: "t6", value: "mobile" },
{ id: "c-accordion", value: "component: accordion" },
{ id: "c-alert-dialog", value: "component: alert dialog" },
{ id: "c-autocomplete", value: "component: autocomplete" },
{ id: "c-avatar", value: "component: avatar" },
{ id: "c-checkbox", value: "component: checkbox" },
{ id: "c-checkbox-group", value: "component: checkbox group" },
{ id: "c-collapsible", value: "component: collapsible" },
{ id: "c-combobox", value: "component: combobox" },
{ id: "c-context-menu", value: "component: context menu" },
{ id: "c-dialog", value: "component: dialog" },
{ id: "c-field", value: "component: field" },
{ id: "c-fieldset", value: "component: fieldset" },
{ id: "c-filterable-menu", value: "component: filterable menu" },
{ id: "c-form", value: "component: form" },
{ id: "c-input", value: "component: input" },
{ id: "c-menu", value: "component: menu" },
{ id: "c-menubar", value: "component: menubar" },
{ id: "c-meter", value: "component: meter" },
{ id: "c-navigation-menu", value: "component: navigation menu" },
{ id: "c-number-field", value: "component: number field" },
{ id: "c-popover", value: "component: popover" },
{ id: "c-preview-card", value: "component: preview card" },
{ id: "c-progress", value: "component: progress" },
{ id: "c-radio", value: "component: radio" },
{ id: "c-scroll-area", value: "component: scroll area" },
{ id: "c-select", value: "component: select" },
{ id: "c-separator", value: "component: separator" },
{ id: "c-slider", value: "component: slider" },
{ id: "c-switch", value: "component: switch" },
{ id: "c-tabs", value: "component: tabs" },
{ id: "c-toast", value: "component: toast" },
{ id: "c-toggle", value: "component: toggle" },
{ id: "c-toggle-group", value: "component: toggle group" },
{ id: "c-toolbar", value: "component: toolbar" },
{ id: "c-tooltip", value: "component: tooltip" },
]
"use client"
import { useState } from "react"
import {
Autocomplete,
AutocompleteContent,
AutocompleteEmpty,
AutocompleteInput,
AutocompleteItem,
AutocompleteList,
} from "@/components/reui/autocomplete"
export function Pattern() {
const [value, setValue] = useState<string>("")
const filteredItems = items.filter((item) =>
item.value.toLowerCase().includes(value.toLowerCase())
)
return (
<div className="w-full max-w-xs">
<Autocomplete
value={value}
onValueChange={setValue}
items={filteredItems}
itemToStringValue={(item: unknown) => (item as Item).value}
>
<AutocompleteInput placeholder="e.g. feature" showTrigger showClear />
<AutocompleteContent>
<AutocompleteEmpty>No items found.</AutocompleteEmpty>
<AutocompleteList>
{(item) => (
<AutocompleteItem key={item.id} value={item}>
{item.value}
</AutocompleteItem>
)}
</AutocompleteList>
</AutocompleteContent>
</Autocomplete>
</div>
)
}
interface Item {
id: string
value: string
}
const items: Item[] = [
{ id: "t1", value: "feature" },
{ id: "t2", value: "fix" },
{ id: "t3", value: "bug" },
{ id: "t4", value: "docs" },
{ id: "t5", value: "internal" },
{ id: "t6", value: "mobile" },
{ id: "c-accordion", value: "component: accordion" },
{ id: "c-alert-dialog", value: "component: alert dialog" },
{ id: "c-autocomplete", value: "component: autocomplete" },
{ id: "c-avatar", value: "component: avatar" },
{ id: "c-checkbox", value: "component: checkbox" },
{ id: "c-checkbox-group", value: "component: checkbox group" },
{ id: "c-collapsible", value: "component: collapsible" },
{ id: "c-combobox", value: "component: combobox" },
{ id: "c-context-menu", value: "component: context menu" },
{ id: "c-dialog", value: "component: dialog" },
{ id: "c-field", value: "component: field" },
{ id: "c-fieldset", value: "component: fieldset" },
{ id: "c-filterable-menu", value: "component: filterable menu" },
{ id: "c-form", value: "component: form" },
{ id: "c-input", value: "component: input" },
{ id: "c-menu", value: "component: menu" },
{ id: "c-menubar", value: "component: menubar" },
{ id: "c-meter", value: "component: meter" },
{ id: "c-navigation-menu", value: "component: navigation menu" },
{ id: "c-number-field", value: "component: number field" },
{ id: "c-popover", value: "component: popover" },
{ id: "c-preview-card", value: "component: preview card" },
{ id: "c-progress", value: "component: progress" },
{ id: "c-radio", value: "component: radio" },
{ id: "c-scroll-area", value: "component: scroll area" },
{ id: "c-select", value: "component: select" },
{ id: "c-separator", value: "component: separator" },
{ id: "c-slider", value: "component: slider" },
{ id: "c-switch", value: "component: switch" },
{ id: "c-tabs", value: "component: tabs" },
{ id: "c-toast", value: "component: toast" },
{ id: "c-toggle", value: "component: toggle" },
{ id: "c-toggle-group", value: "component: toggle group" },
{ id: "c-toolbar", value: "component: toolbar" },
{ id: "c-tooltip", value: "component: tooltip" },
]
"use client"
import { useMemo, useState } from "react"
import {
Autocomplete,
AutocompleteCollection,
AutocompleteContent,
AutocompleteEmpty,
AutocompleteGroup,
AutocompleteGroupLabel,
AutocompleteInput,
AutocompleteItem,
AutocompleteList,
} from "@/components/reui/autocomplete"
import { Autocomplete as AutocompletePrimitive } from "@base-ui/react/autocomplete"
import {
Avatar,
AvatarFallback,
AvatarImage,
} from "@/components/ui/avatar"
export function Pattern() {
const [value, setValue] = useState("")
const [open, setOpen] = useState(false)
const { contains } = AutocompletePrimitive.useFilter({ sensitivity: "base" })
const filteredItems = useMemo(() => {
if (!value) return groupedUsers
return groupedUsers
.map((group) => ({
...group,
items: (group.items || []).filter(
(item) =>
contains(item.name || "", value) ||
contains(item.group || "", value) ||
contains(item.position || "", value)
),
}))
.filter((group) => group.items && group.items.length > 0)
}, [value, contains])
return (
<div className="w-full max-w-xs">
<Autocomplete
items={filteredItems}
value={value}
onValueChange={setValue}
open={open}
onOpenChange={setOpen}
itemToStringValue={(item: unknown) => (item as User).name}
filter={null}
>
<AutocompleteInput placeholder="e.g. John, Developer, Marketing" />
{open && (
<AutocompleteContent className="pt-0">
{filteredItems.length === 0 ? (
<AutocompleteEmpty>No matching users found.</AutocompleteEmpty>
) : (
<AutocompleteList className="not-empty:py-0">
{(group: UserGroup) => (
<AutocompleteGroup
key={group.group}
items={group.items}
className="py-0"
>
<AutocompleteGroupLabel className="bg-background text-muted-foreground sticky top-0 z-10 me-1.5 py-2.5 text-xs font-medium">
{group.group}
</AutocompleteGroupLabel>
<AutocompleteCollection>
{(item: User) => (
<AutocompleteItem
key={item.id}
value={item}
className="flex items-center gap-2.5 rounded-lg"
>
<Avatar className="size-9">
<AvatarImage
src={item.avatar}
alt={item.name || "User"}
/>
<AvatarFallback>
{(item.name || "U")
.split(" ")
.map((n) => n[0])
.join("")}
</AvatarFallback>
</Avatar>
<div className="min-w-0 flex-1">
<div className="truncate font-medium">
{item.name || "Unknown"}
</div>
<div className="text-muted-foreground truncate text-sm">
{item.position || "No position available"}
</div>
</div>
</AutocompleteItem>
)}
</AutocompleteCollection>
</AutocompleteGroup>
)}
</AutocompleteList>
)}
</AutocompleteContent>
)}
</Autocomplete>
</div>
)
}
interface User {
id: string
name: string
group: string
position: string
avatar: string
status: "Active" | "Inactive" | "Away"
}
interface UserGroup {
group: string
items: User[]
}
const usersData: User[] = [
// Development Team
{
id: "john-doe",
name: "John Doe",
group: "Development Team",
position: "Senior Frontend Developer",
avatar: "https://randomuser.me/api/portraits/men/1.jpg",
status: "Active",
},
{
id: "jane-smith",
name: "Jane Smith",
group: "Development Team",
position: "Full Stack Developer",
avatar: "https://randomuser.me/api/portraits/women/2.jpg",
status: "Active",
},
{
id: "mike-wilson",
name: "Mike Wilson",
group: "Development Team",
position: "Backend Developer",
avatar: "https://randomuser.me/api/portraits/men/3.jpg",
status: "Active",
},
{
id: "sarah-johnson",
name: "Sarah Johnson",
group: "Development Team",
position: "DevOps Engineer",
avatar: "https://randomuser.me/api/portraits/women/4.jpg",
status: "Away",
},
{
id: "david-brown",
name: "David Brown",
group: "Development Team",
position: "Mobile Developer",
avatar: "https://randomuser.me/api/portraits/men/5.jpg",
status: "Active",
},
{
id: "lisa-garcia",
name: "Lisa Garcia",
group: "Development Team",
position: "UI/UX Developer",
avatar: "https://randomuser.me/api/portraits/women/6.jpg",
status: "Active",
},
// Design Team
{
id: "alex-martinez",
name: "Alex Martinez",
group: "Design Team",
position: "Lead UX Designer",
avatar: "https://randomuser.me/api/portraits/men/7.jpg",
status: "Active",
},
{
id: "emma-davis",
name: "Emma Davis",
group: "Design Team",
position: "UI Designer",
avatar: "https://randomuser.me/api/portraits/women/8.jpg",
status: "Active",
},
{
id: "chris-taylor",
name: "Chris Taylor",
group: "Design Team",
position: "Product Designer",
avatar: "https://randomuser.me/api/portraits/men/9.jpg",
status: "Active",
},
{
id: "olivia-anderson",
name: "Olivia Anderson",
group: "Design Team",
position: "Visual Designer",
avatar: "https://randomuser.me/api/portraits/women/10.jpg",
status: "Inactive",
},
// Marketing Team
{
id: "james-moore",
name: "James Moore",
group: "Marketing Team",
position: "Marketing Manager",
avatar: "https://randomuser.me/api/portraits/men/11.jpg",
status: "Active",
},
{
id: "sophia-white",
name: "Sophia White",
group: "Marketing Team",
position: "Content Marketing Specialist",
avatar: "https://randomuser.me/api/portraits/women/12.jpg",
status: "Active",
},
{
id: "william-harris",
name: "William Harris",
group: "Marketing Team",
position: "Digital Marketing Specialist",
avatar: "https://randomuser.me/api/portraits/men/13.jpg",
status: "Active",
},
{
id: "ava-martin",
name: "Ava Martin",
group: "Marketing Team",
position: "Social Media Manager",
avatar: "https://randomuser.me/api/portraits/women/14.jpg",
status: "Away",
},
// Sales Team
{
id: "ethan-thompson",
name: "Ethan Thompson",
group: "Sales Team",
position: "Sales Director",
avatar: "https://randomuser.me/api/portraits/men/15.jpg",
status: "Active",
},
{
id: "mia-garcia",
name: "Mia Garcia",
group: "Sales Team",
position: "Account Executive",
avatar: "https://randomuser.me/api/portraits/women/16.jpg",
status: "Active",
},
{
id: "noah-martinez",
name: "Noah Martinez",
group: "Sales Team",
position: "Sales Representative",
avatar: "https://randomuser.me/api/portraits/men/17.jpg",
status: "Active",
},
{
id: "isabella-rodriguez",
name: "Isabella Rodriguez",
group: "Sales Team",
position: "Business Development Manager",
avatar: "https://randomuser.me/api/portraits/women/18.jpg",
status: "Active",
},
// Management Team
{
id: "lucas-lee",
name: "Lucas Lee",
group: "Management Team",
position: "CEO",
avatar: "https://randomuser.me/api/portraits/men/19.jpg",
status: "Active",
},
{
id: "charlotte-walker",
name: "Charlotte Walker",
group: "Management Team",
position: "CTO",
avatar: "https://randomuser.me/api/portraits/women/20.jpg",
status: "Active",
},
{
id: "benjamin-hall",
name: "Benjamin Hall",
group: "Management Team",
position: "VP of Engineering",
avatar: "https://randomuser.me/api/portraits/men/21.jpg",
status: "Active",
},
{
id: "amelia-allen",
name: "Amelia Allen",
group: "Management Team",
position: "VP of Marketing",
avatar: "https://randomuser.me/api/portraits/women/22.jpg",
status: "Active",
},
// Support Team
{
id: "henry-young",
name: "Henry Young",
group: "Support Team",
position: "Customer Success Manager",
avatar: "https://randomuser.me/api/portraits/men/23.jpg",
status: "Active",
},
{
id: "grace-king",
name: "Grace King",
group: "Support Team",
position: "Technical Support Specialist",
avatar: "https://randomuser.me/api/portraits/women/24.jpg",
status: "Active",
},
{
id: "sebastian-wright",
name: "Sebastian Wright",
group: "Support Team",
position: "Customer Support Representative",
avatar: "https://randomuser.me/api/portraits/men/25.jpg",
status: "Away",
},
{
id: "lily-lopez",
name: "Lily Lopez",
group: "Support Team",
position: "Help Desk Technician",
avatar: "https://randomuser.me/api/portraits/women/26.jpg",
status: "Active",
},
]
function groupUsers(users: User[]): UserGroup[] {
const groups: { [key: string]: User[] } = {}
users.forEach((item) => {
;(groups[item.group] ??= []).push(item)
})
// Sort by status within each group (Active first, then Away, then Inactive)
Object.keys(groups).forEach((group) => {
groups[group].sort((a, b) => {
const statusOrder = { Active: 0, Away: 1, Inactive: 2 }
return statusOrder[a.status] - statusOrder[b.status]
})
})
const order = [
"Management Team",
"Development Team",
"Design Team",
"Marketing Team",
"Sales Team",
"Support Team",
]
return order.map((group) => ({ group, items: groups[group] ?? [] }))
}
const groupedUsers: UserGroup[] = groupUsers(usersData)
"use client"
import { ReactNode, useEffect, useState } from "react"
import {
Autocomplete,
AutocompleteContent,
AutocompleteInput,
AutocompleteItem,
AutocompleteList,
AutocompleteStatus,
} from "@/components/reui/autocomplete"
import { Autocomplete as AutocompletePrimitive } from "@base-ui/react/autocomplete"
import {
Avatar,
AvatarFallback,
AvatarImage,
} from "@/components/ui/avatar"
import { LoaderCircleIcon } from 'lucide-react'
export function Pattern() {
const [searchValue, setSearchValue] = useState("")
const [isLoading, setIsLoading] = useState(false)
const [searchResults, setSearchResults] = useState<Developer[]>([])
const [error, setError] = useState<string | null>(null)
const { contains } = AutocompletePrimitive.useFilter({ sensitivity: "base" })
useEffect(() => {
if (!searchValue) {
setSearchResults([])
setIsLoading(false)
return undefined
}
setIsLoading(true)
setError(null)
let ignore = false
async function fetchDevelopers() {
try {
const results = await searchDevelopers(searchValue, contains)
if (!ignore) {
setSearchResults(results)
}
} catch {
if (!ignore) {
setError("Failed to fetch developers. Please try again.")
setSearchResults([])
}
} finally {
if (!ignore) {
setIsLoading(false)
}
}
}
const timeoutId = setTimeout(fetchDevelopers, 300)
return () => {
clearTimeout(timeoutId)
ignore = true
}
}, [searchValue, contains])
let status: ReactNode = ""
if (isLoading) {
status = (
<div className="flex items-center gap-2">
<LoaderCircleIcon className="size-4 animate-spin" />
Searching developers...
</div>
)
} else if (error) {
status = error
} else if (searchResults.length === 0 && searchValue) {
status = `No developers found for "${searchValue}"`
} else if (searchResults.length > 0) {
status = `${searchResults.length} developer${searchResults.length === 1 ? "" : "s"} found`
} else if (!searchValue) {
status = "Start typing to search developers..."
}
const shouldRenderPopup = searchValue !== ""
return (
<div className="w-full max-w-xs">
<Autocomplete
items={searchResults}
value={searchValue}
onValueChange={setSearchValue}
itemToStringValue={(item: unknown) => (item as Developer).name}
filter={null}
>
<AutocompleteInput
placeholder="e.g. John Smith, React, San Francisco"
showTrigger
showClear
/>
{shouldRenderPopup && (
<AutocompleteContent>
<AutocompleteStatus>{status}</AutocompleteStatus>
<AutocompleteList>
{(developer: Developer) => (
<AutocompleteItem
key={developer.id}
value={developer}
className="rounded-lg"
>
<div className="flex items-center gap-2.5 truncate">
<Avatar className="size-9">
<AvatarImage
src={developer.avatar}
alt={developer.name}
/>
<AvatarFallback>
{developer.name
.split(" ")
.map((n) => n[0])
.join("")}
</AvatarFallback>
</Avatar>
<div className="min-w-0 flex-1">
<div className="truncate font-medium">
{developer.name}
</div>
<div className="text-muted-foreground truncate text-sm">
{developer.role} • {developer.location}
</div>
</div>
</div>
</AutocompleteItem>
)}
</AutocompleteList>
</AutocompleteContent>
)}
</Autocomplete>
</div>
)
}
async function searchDevelopers(
query: string,
filter: (item: string, query: string) => boolean
): Promise<Developer[]> {
// Simulate network delay
await new Promise((resolve) => {
setTimeout(resolve, Math.random() * 800 + 200)
})
// Simulate occasional network errors (2% chance)
if (Math.random() < 0.02 || query === "error") {
throw new Error("Network error")
}
return topDevelopers.filter(
(developer) =>
filter(developer.name, query) ||
filter(developer.role, query) ||
filter(developer.location, query) ||
developer.skills.some((skill) => filter(skill, query))
)
}
interface Developer {
id: string
name: string
role: string
location: string
skills: string[]
experience: number
rating: number
avatar: string
}
const topDevelopers: Developer[] = [
{
id: "1",
name: "Alex Chen",
role: "Senior Full-Stack Developer",
location: "San Francisco, CA",
skills: ["React", "Node.js", "TypeScript", "AWS", "Docker"],
experience: 8,
rating: 4.9,
avatar: "https://randomuser.me/api/portraits/men/1.jpg",
},
{
id: "2",
name: "Sarah Johnson",
role: "Frontend Architect",
location: "New York, NY",
skills: ["Vue.js", "JavaScript", "CSS", "Webpack", "Figma"],
experience: 10,
rating: 4.8,
avatar: "https://randomuser.me/api/portraits/women/2.jpg",
},
{
id: "3",
name: "Michael Rodriguez",
role: "Backend Engineer",
location: "Austin, TX",
skills: ["Python", "Django", "PostgreSQL", "Redis", "Kubernetes"],
experience: 6,
rating: 4.7,
avatar: "https://randomuser.me/api/portraits/men/3.jpg",
},
{
id: "4",
name: "Emily Wang",
role: "DevOps Engineer",
location: "Seattle, WA",
skills: ["AWS", "Terraform", "Jenkins", "Docker", "Linux"],
experience: 7,
rating: 4.9,
avatar: "https://randomuser.me/api/portraits/women/4.jpg",
},
{
id: "5",
name: "David Kim",
role: "Mobile Developer",
location: "Los Angeles, CA",
skills: ["React Native", "Swift", "Kotlin", "Firebase", "GraphQL"],
experience: 5,
rating: 4.6,
avatar: "https://randomuser.me/api/portraits/men/5.jpg",
},
{
id: "6",
name: "Lisa Thompson",
role: "Data Engineer",
location: "Boston, MA",
skills: ["Python", "Spark", "Airflow", "Snowflake", "dbt"],
experience: 9,
rating: 4.8,
avatar: "https://randomuser.me/api/portraits/women/6.jpg",
},
{
id: "7",
name: "James Wilson",
role: "Cloud Solutions Architect",
location: "Chicago, IL",
skills: ["AWS", "Azure", "Terraform", "Kubernetes", "Microservices"],
experience: 12,
rating: 4.9,
avatar: "https://randomuser.me/api/portraits/men/7.jpg",
},
{
id: "8",
name: "Maria Garcia",
role: "UI/UX Developer",
location: "Miami, FL",
skills: ["React", "Figma", "CSS-in-JS", "Storybook", "Accessibility"],
experience: 4,
rating: 4.5,
avatar: "https://randomuser.me/api/portraits/women/8.jpg",
},
{
id: "9",
name: "Robert Taylor",
role: "Machine Learning Engineer",
location: "Denver, CO",
skills: ["Python", "TensorFlow", "PyTorch", "MLOps", "Docker"],
experience: 6,
rating: 4.7,
avatar: "https://randomuser.me/api/portraits/men/9.jpg",
},
{
id: "10",
name: "Jennifer Lee",
role: "Blockchain Developer",
location: "San Diego, CA",
skills: ["Solidity", "Web3.js", "Ethereum", "Smart Contracts", "Rust"],
experience: 5,
rating: 4.6,
avatar: "https://randomuser.me/api/portraits/women/10.jpg",
},
{
id: "11",
name: "Christopher Brown",
role: "Security Engineer",
location: "Portland, OR",
skills: ["Cybersecurity", "Penetration Testing", "OWASP", "SIEM", "Python"],
experience: 8,
rating: 4.8,
avatar: "https://randomuser.me/api/portraits/men/11.jpg",
},
{
id: "12",
name: "Amanda Davis",
role: "Game Developer",
location: "Orlando, FL",
skills: ["Unity", "C#", "Unreal Engine", "3D Modeling", "VR/AR"],
experience: 7,
rating: 4.7,
avatar: "https://randomuser.me/api/portraits/women/12.jpg",
},
{
id: "13",
name: "Kevin Zhang",
role: "AI Research Engineer",
location: "Palo Alto, CA",
skills: ["Python", "PyTorch", "Transformers", "NLP", "Computer Vision"],
experience: 6,
rating: 4.9,
avatar: "https://randomuser.me/api/portraits/men/13.jpg",
},
{
id: "14",
name: "Rachel Green",
role: "QA Automation Engineer",
location: "Phoenix, AZ",
skills: ["Selenium", "Cypress", "Jest", "Python", "Test Automation"],
experience: 5,
rating: 4.6,
avatar: "https://randomuser.me/api/portraits/women/14.jpg",
},
{
id: "15",
name: "Daniel Martinez",
role: "System Administrator",
location: "Dallas, TX",
skills: [
"Linux",
"Windows Server",
"Active Directory",
"PowerShell",
"VMware",
],
experience: 10,
rating: 4.8,
avatar: "https://randomuser.me/api/portraits/men/15.jpg",
},
{
id: "16",
name: "Sophie Anderson",
role: "Product Manager",
location: "San Jose, CA",
skills: [
"Product Strategy",
"Agile",
"Analytics",
"User Research",
"Figma",
],
experience: 8,
rating: 4.7,
avatar: "https://randomuser.me/api/portraits/women/16.jpg",
},
{
id: "17",
name: "Mark Thompson",
role: "Database Administrator",
location: "Atlanta, GA",
skills: ["PostgreSQL", "MySQL", "MongoDB", "Redis", "Performance Tuning"],
experience: 11,
rating: 4.9,
avatar: "https://randomuser.me/api/portraits/men/17.jpg",
},
{
id: "18",
name: "Jessica White",
role: "Technical Writer",
location: "Raleigh, NC",
skills: [
"Technical Writing",
"Markdown",
"API Documentation",
"Git",
"Confluence",
],
experience: 6,
rating: 4.5,
avatar: "https://randomuser.me/api/portraits/women/18.jpg",
},
{
id: "19",
name: "Andrew Clark",
role: "Site Reliability Engineer",
location: "Nashville, TN",
skills: [
"Monitoring",
"Incident Response",
"Python",
"Terraform",
"Kubernetes",
],
experience: 7,
rating: 4.8,
avatar: "https://randomuser.me/api/portraits/men/19.jpg",
},
{
id: "20",
name: "Nicole Taylor",
role: "Frontend Developer",
location: "Minneapolis, MN",
skills: ["Angular", "TypeScript", "RxJS", "SCSS", "Jest"],
experience: 4,
rating: 4.6,
avatar: "https://randomuser.me/api/portraits/women/20.jpg",
},
{
id: "21",
name: "Ryan Murphy",
role: "Backend Developer",
location: "Kansas City, MO",
skills: ["Java", "Spring Boot", "Microservices", "MongoDB", "Docker"],
experience: 6,
rating: 4.7,
avatar: "https://randomuser.me/api/portraits/men/21.jpg",
},
{
id: "22",
name: "Stephanie Lewis",
role: "Full-Stack Developer",
location: "Salt Lake City, UT",
skills: ["React", "Node.js", "GraphQL", "PostgreSQL", "AWS"],
experience: 5,
rating: 4.6,
avatar: "https://randomuser.me/api/portraits/women/22.jpg",
},
{
id: "23",
name: "Brandon Wright",
role: "Cloud Engineer",
location: "Las Vegas, NV",
skills: ["AWS", "Terraform", "Docker", "Kubernetes", "Python"],
experience: 8,
rating: 4.8,
avatar: "https://randomuser.me/api/portraits/men/23.jpg",
},
{
id: "24",
name: "Ashley Hall",
role: "DevOps Engineer",
location: "Columbus, OH",
skills: ["CI/CD", "Jenkins", "GitLab", "Docker", "AWS"],
experience: 6,
rating: 4.7,
avatar: "https://randomuser.me/api/portraits/women/24.jpg",
},
{
id: "25",
name: "Tyler Young",
role: "Mobile App Developer",
location: "Tampa, FL",
skills: ["Flutter", "Dart", "Firebase", "REST APIs", "Git"],
experience: 4,
rating: 4.5,
avatar: "https://randomuser.me/api/portraits/men/25.jpg",
},
]
import {
Autocomplete,
AutocompleteContent,
AutocompleteEmpty,
AutocompleteInput,
AutocompleteItem,
AutocompleteList,
} from "@/components/reui/autocomplete"
export function Pattern() {
return (
<div className="w-full max-w-xs">
<Autocomplete items={items}>
<AutocompleteInput
placeholder="Search items"
size="sm"
showTrigger
showClear
/>
<AutocompleteContent>
<AutocompleteEmpty>No items found.</AutocompleteEmpty>
<AutocompleteList>
{(item) => (
<AutocompleteItem key={item.id} value={item.value}>
{item.value}
</AutocompleteItem>
)}
</AutocompleteList>
</AutocompleteContent>
</Autocomplete>
</div>
)
}
interface Item {
id: string
value: string
}
const items: Item[] = [
{ id: "t1", value: "Feature" },
{ id: "t2", value: "Fix" },
{ id: "t3", value: "Bug" },
{ id: "t4", value: "Docs" },
{ id: "t5", value: "Internal" },
{ id: "t6", value: "Mobile" },
{ id: "c-accordion", value: "component: Accordion" },
{ id: "c-alert-dialog", value: "component: Alert Dialog" },
{ id: "c-autocomplete", value: "component: Autocomplete" },
{ id: "c-avatar", value: "component: Avatar" },
{ id: "c-checkbox", value: "component: Checkbox" },
{ id: "c-checkbox-group", value: "component: Checkbox Group" },
{ id: "c-collapsible", value: "component: Collapsible" },
{ id: "c-combobox", value: "component: Combobox" },
{ id: "c-context-menu", value: "component: Context Menu" },
{ id: "c-dialog", value: "component: Dialog" },
{ id: "c-field", value: "component: Field" },
{ id: "c-fieldset", value: "component: Fieldset" },
{ id: "c-filterable-menu", value: "component: Filterable Menu" },
{ id: "c-form", value: "component: Form" },
{ id: "c-input", value: "component: Input" },
{ id: "c-menu", value: "component: Menu" },
{ id: "c-menubar", value: "component: Menubar" },
{ id: "c-meter", value: "component: Meter" },
{ id: "c-navigation-menu", value: "component: Navigation Menu" },
{ id: "c-number-field", value: "component: Number Field" },
{ id: "c-popover", value: "component: Popover" },
{ id: "c-preview-card", value: "component: Preview Card" },
{ id: "c-progress", value: "component: Progress" },
{ id: "c-radio", value: "component: Radio" },
{ id: "c-scroll-area", value: "component: Scroll Area" },
{ id: "c-select", value: "component: Select" },
{ id: "c-separator", value: "component: Separator" },
{ id: "c-slider", value: "component: Slider" },
{ id: "c-switch", value: "component: Switch" },
{ id: "c-tabs", value: "component: Tabs" },
{ id: "c-toast", value: "component: Toast" },
{ id: "c-toggle", value: "component: Toggle" },
{ id: "c-toggle-group", value: "component: Toggle Group" },
{ id: "c-toolbar", value: "component: Toolbar" },
{ id: "c-tooltip", value: "component: Tooltip" },
]
import {
Autocomplete,
AutocompleteContent,
AutocompleteEmpty,
AutocompleteInput,
AutocompleteItem,
AutocompleteList,
} from "@/components/reui/autocomplete"
export function Pattern() {
return (
<div className="w-full max-w-xs">
<Autocomplete items={items}>
<AutocompleteInput
placeholder="Search items"
size="lg"
showTrigger
showClear
/>
<AutocompleteContent>
<AutocompleteEmpty>No items found.</AutocompleteEmpty>
<AutocompleteList>
{(item) => (
<AutocompleteItem key={item.id} value={item.value}>
{item.value}
</AutocompleteItem>
)}
</AutocompleteList>
</AutocompleteContent>
</Autocomplete>
</div>
)
}
interface Item {
id: string
value: string
}
const items: Item[] = [
{ id: "t1", value: "Feature" },
{ id: "t2", value: "Fix" },
{ id: "t3", value: "Bug" },
{ id: "t4", value: "Docs" },
{ id: "t5", value: "Internal" },
{ id: "t6", value: "Mobile" },
{ id: "c-accordion", value: "component: Accordion" },
{ id: "c-alert-dialog", value: "component: Alert Dialog" },
{ id: "c-autocomplete", value: "component: Autocomplete" },
{ id: "c-avatar", value: "component: Avatar" },
{ id: "c-checkbox", value: "component: Checkbox" },
{ id: "c-checkbox-group", value: "component: Checkbox Group" },
{ id: "c-collapsible", value: "component: Collapsible" },
{ id: "c-combobox", value: "component: Combobox" },
{ id: "c-context-menu", value: "component: Context Menu" },
{ id: "c-dialog", value: "component: Dialog" },
{ id: "c-field", value: "component: Field" },
{ id: "c-fieldset", value: "component: Fieldset" },
{ id: "c-filterable-menu", value: "component: Filterable Menu" },
{ id: "c-form", value: "component: Form" },
{ id: "c-input", value: "component: Input" },
{ id: "c-menu", value: "component: Menu" },
{ id: "c-menubar", value: "component: Menubar" },
{ id: "c-meter", value: "component: Meter" },
{ id: "c-navigation-menu", value: "component: Navigation Menu" },
{ id: "c-number-field", value: "component: Number Field" },
{ id: "c-popover", value: "component: Popover" },
{ id: "c-preview-card", value: "component: Preview Card" },
{ id: "c-progress", value: "component: Progress" },
{ id: "c-radio", value: "component: Radio" },
{ id: "c-scroll-area", value: "component: Scroll Area" },
{ id: "c-select", value: "component: Select" },
{ id: "c-separator", value: "component: Separator" },
{ id: "c-slider", value: "component: Slider" },
{ id: "c-switch", value: "component: Switch" },
{ id: "c-tabs", value: "component: Tabs" },
{ id: "c-toast", value: "component: Toast" },
{ id: "c-toggle", value: "component: Toggle" },
{ id: "c-toggle-group", value: "component: Toggle Group" },
{ id: "c-toolbar", value: "component: Toolbar" },
{ id: "c-tooltip", value: "component: Tooltip" },
]