Kaapi UI
← Back to Design System

Select

Advanced select component with icons, avatars, custom content, groups, scrollable items, and form integration.

Basic Select

<Select
    items={[
        { id: "apple", label: "Apple" },
        { id: "orange", label: "Orange" },
        { id: "banana", label: "Banana" }
    ]}
    placeholder="Select a fruit"
/>

Disabled Select

<Select
    disabled
    items={basicItems}
    placeholder="Select a fruit"
/>

Select with Icons and Supporting Text

<Select
    items={[
        {
            id: "user",
            label: "User",
            icon: <User01 className="w-4 h-4" />,
            supportingText: "Limited access",
        },
        {
            id: "admin",
            label: "Administrator",
            icon: <Shield01 className="w-4 h-4" />,
            supportingText: "Full access",
        },
        {
            id: "moderator",
            label: "Moderator",
            icon: <Star01 className="w-4 h-4" />,
            supportingText: "Content management",
        },
    ]}
    placeholder="Select a role"
/>

Select with Avatars

<Select
    items={[
        {
            id: "john",
            label: "John Doe",
            value: "john",
            avatarUrl: "/images/avatar-1.png",
            supportingText: "john@example.com",
        },
        {
            id: "jane",
            value: "jane",
            label: "Jane Smith",
            avatarUrl: "/images/avatar-2.png",
            supportingText: "jane@example.com",
        },
    ]}
    placeholder="Select a user"
/>

Custom Item Rendering

<Select
    items={[
        {
            id: "file1",
            label: "Important Document.pdf",
            icon: <File01 className="w-4 h-4" />,
            supportingText: "Modified 2 hours ago",
        },
        {
            id: "file2",
            label: "Presentation.pptx",
            icon: <File01 className="w-4 h-4" />,
            supportingText: "Modified yesterday",
        },
    ]}
    placeholder="Select a file"
    renderItem={(item) => (
        <div className="flex items-center justify-between w-full">
            <div className="flex items-center gap-2">
                {item.icon}
                <span>{item.label}</span>
            </div>
            <span className="text-xs text-tertiary">
                {item.supportingText}
            </span>
        </div>
    )}
/>

Mixed Content with Groups and Separators

<Select
    items={[
        {
            id: "docs",
            type: "group",
            label: "Recent Files",
            items: [
                {
                    id: "doc1",
                    label: "Report.pdf",
                    icon: <File01 className="w-4 h-4" />,
                    supportingText: "2.4 MB",
                },
            ],
        },
        { id: "sep1", type: "separator" },
        {
            id: "projects-group",
            type: "group",
            label: "Projects",
            items: [
                {
                    id: "proj1",
                    label: "Project Alpha",
                    supportingText: "Active",
                    icon: <Star01 className="w-4 h-4" />,
                },
                {
                    id: "proj2",
                    label: "Project Beta",
                    supportingText: "On hold",
                },
            ],
        },
    ]}
    placeholder="Select an item"
    triggerClassName="w-[360px]"
/>

Scrollable Select With Disabled Item

<Select
    items={[
        {
            id: "north-america",
            type: "group",
            label: "North America",
            items: [
                { id: "est", label: "Eastern Standard Time (EST)" },
                { id: "cst", label: "Central Standard Time (CST)", disabled: true },
                { id: "mst", label: "Mountain Standard Time (MST)" },
                { id: "pst", label: "Pacific Standard Time (PST)" },
                { id: "akst", label: "Alaska Standard Time (AKST)" },
                { id: "hst", label: "Hawaii Standard Time (HST)" },
            ],
        },
        {
            id: "europe-africa",
            type: "group",
            label: "Europe & Africa",
            items: [
                { id: "gmt", label: "Greenwich Mean Time (GMT)" },
                { id: "cet", label: "Central European Time (CET)" },
                { id: "eet", label: "Eastern European Time (EET)" },
                { id: "west", label: "Western European Summer Time (WEST)" },
                { id: "cat", label: "Central Africa Time (CAT)" },
                { id: "eat", label: "East Africa Time (EAT)" },
            ],
        },
    ]}
    placeholder="Select a timezone"
    triggerClassName="w-[360px]"
/>

Combobox

 
<Combobox
    placeholder="Search priority..."
    items={priorities}
    value={priority}
    onValueChange={setPriority}
    size="md"
/>

MultiSelect

 
<MultiSelect
    placeholder="Search"
    items={avatarItems}
    value={userValues}
    onValueChange={setUserValues}
    size="sm"
/>

Select in Form


import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";

 const formSchema = z.object({
        email: z.email({
            message: "Please select an email to display.",
        }),
        framework: z.string({
            message: "Please select a framework.",
        }),
        users: z.array(z.string()).min(1, "Please select at least one user."),
    });

function onSubmit(data: z.infer<typeof formSchema>) {
        toast("You submitted the following values", {
            description: (
                <pre className="mt-2 w-[320px] rounded-md bg-neutral-950 p-4">
                    <code className="text-white">{JSON.stringify(data, null, 2)}</code>
                </pre>
            ),
        });
}
<Form {...form}>
    <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
        <SelectForm
            control={form.control}
            name="email"
            label="Email"
            labelTooltip="This is a tooltip"
            placeholder="Select a verified email to display"
            items={emailItems}
            isRequired
        />
        <ComboboxForm
            control={form.control}
            name="framework"
            label="Framework"
            labelTooltip="This is a tooltip"
            placeholder="Select a framework"
            items={frameworks}
            isRequired
        />
        <MultiSelectForm
            control={form.control}
            name="users"
            label="Users"
            labelTooltip="This is a tooltip"
            placeholder="Select some users"
            items={avatarItems}
            isRequired
        />
        <Button type="submit">Submit</Button>
    </form>
</Form>

API Reference

Select Props

PropsTypeDefaultDescription
itemsSelectItemData[][]List of items to display in the select (items, groups, labels, separators)
value?stringSelected value (controlled)
onValueChange?(value: string) => voidCallback called when value changes
placeholder?string"Select an option..."Text displayed when no value is selected
size?"sm" | "default""default"Size of the trigger
disabled?booleanfalseDisables the select
showIcon?booleanfalseShow icon in the trigger for selected item
showAvatar?booleanfalseShow avatar in the trigger for selected item
renderItem?(item: SelectItemData) => ReactNodeCustom render function for items
triggerClassName?stringCustom class for the trigger
contentClassName?stringCustom class for the content
itemClassName?stringCustom class for items

SelectItemData

PropsTypeDefaultDescription
idstringUnique identifier for the item
label?React.ReactNodeText or element displayed
value?stringValue used for selection (defaults to id)
disabled?booleanfalseDisables the item
type?"item" | "separator" | "group""item"Type of element
icon?React.ReactNodeIcon to display
avatarUrl?stringAvatar image URL
supportingText?stringSecondary text displayed below label
customContent?React.ReactNodeCompletely custom content for the item
items?SelectItemData[][]Sub-items for groups

Combobox and MutiSelect Props

PropsTypeDefaultDescription
placeholder?string"Search"Placeholder text displayed in the input field.
shortcut?booleanfalseWhether to display the keyboard shortcut hint (⌘K).
size?"sm" | "md""sm"Controls the input size and spacing.
items?ComboboxItemBase[][]List of items available in the combobox.
value?string | nullThe controlled selected value.
onValueChange?function: (value: string | null) => voidCallback fired when the selected value changes.
disabled?booleanfalseWhether the combobox is disabled.
inputClassName?stringCustom class applied to the input container.
shortcutClassName?stringCustom class applied to the shortcut indicator.
contentClassName?stringCustom class applied to the dropdown content.
emptyMessage?string"No results found."Message displayed when no items match the search input.
children?React.ReactNodeOptional custom rendering of items. If provided, it overrides items.

SelectForm, ComboboxForm and MultiSelectForm Props

Extends all Select type props plus the following form-specific props:

PropsTypeDefaultDescription
controlControlReact Hook Form control object
namestringField name
label?stringField label
description?stringField description
isRequired?booleanfalseShows required indicator