Components
Loading preview...
Accessible select built on React Aria, from HeroUI v3. A collapsible listbox with single and multiple selection, descriptions, grouped sections with headers and separators, disabled options, controlled value, primary/secondary variants, and full keyboard + typeahead support. Compound API: Select / Select.Trigger / Select.Value / Select.Indicator / Select.Popover + ListBox / ListBox.Item / ListBox.ItemIndicator / ListBox.Section / Header / Separator / Label / Description / FieldError.
npx shadcn@latest add https://21st.dev/r/hero_ui/heroui-select"use client"
import {
Avatar,
AvatarFallback,
AvatarImage,
Description,
Label,
ListBox,
Select,
} from "@/components/ui/heroui-select"
export default function CustomValue() {
const users = [
{
avatarUrl: "https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/blue.jpg",
email: "bob@heroui.com",
fallback: "B",
id: "1",
name: "Bob",
},
{
avatarUrl: "https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/green.jpg",
email: "fred@heroui.com",
fallback: "F",
id: "2",
name: "Fred",
},
{
avatarUrl: "https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/purple.jpg",
email: "martha@heroui.com",
fallback: "M",
id: "3",
name: "Martha",
},
{
avatarUrl: "https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/red.jpg",
email: "john@heroui.com",
fallback: "J",
id: "4",
name: "John",
},
{
avatarUrl: "https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/orange.jpg",
email: "jane@heroui.com",
fallback: "J",
id: "5",
name: "Jane",
},
]
return (
<div className="flex min-h-[360px] w-full items-center justify-center p-8">
<Select className="w-[256px]" placeholder="Select a user">
<Label>User</Label>
<Select.Trigger>
<Select.Value>
{({ defaultChildren, isPlaceholder, state }) => {
if (isPlaceholder || state.selectedItems.length === 0) {
return defaultChildren
}
const selectedItems = state.selectedItems
if (selectedItems.length > 1) {
return `${selectedItems.length} users selected`
}
const selectedItem = users.find((user) => user.id === selectedItems[0]?.key)
if (!selectedItem) {
return defaultChildren
}
return (
<div className="flex items-center gap-2">
<Avatar className="size-4" size="sm">
<AvatarImage src={selectedItem.avatarUrl} />
<AvatarFallback>{selectedItem.fallback}</AvatarFallback>
</Avatar>
<span>{selectedItem.name}</span>
</div>
)
}}
</Select.Value>
<Select.Indicator />
</Select.Trigger>
<Select.Popover>
<ListBox>
{users.map((user) => (
<ListBox.Item key={user.id} id={user.id} textValue={user.name}>
<Avatar size="sm">
<AvatarImage src={user.avatarUrl} />
<AvatarFallback>{user.fallback}</AvatarFallback>
</Avatar>
<div className="flex flex-col">
<Label>{user.name}</Label>
<Description>{user.email}</Description>
</div>
<ListBox.ItemIndicator />
</ListBox.Item>
))}
</ListBox>
</Select.Popover>
</Select>
</div>
)
}