Select
A dropdown component that allows users to choose from a list of options.
Overview
The Select component provides a dropdown interface for choosing from a list of options, with support for grouping, clearing, custom indicators, and advanced rendering. Built on Base UI primitives, it offers full keyboard navigation and accessibility features out of the box.
Usage
import {
Select,
SelectTrigger,
SelectValue,
SelectContent,
SelectItem,
SelectGroup,
SelectLabel,
SelectSeparator,
SelectClear,
SelectIndicator,
} from "@tilt-legal/cubitt-components/primitives";// Basic select
const fruitItems = [
{ label: "Apple", value: "apple" },
{ label: "Banana", value: "banana" },
{ label: "Cherry", value: "cherry" },
];
<Select items={fruitItems}>
<SelectTrigger>
<SelectValue placeholder="Select a fruit" />
</SelectTrigger>
<SelectContent>
{fruitItems.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</SelectContent>
</Select>Pass items whenever you rely on the default <SelectValue /> output. Without that label map, the trigger can only fall back to raw values.
For complex trigger displays (icons, avatars, badges) use a render function in SelectValue for custom trigger display.
const items = [
{ label: "Alan Bold", value: "1", avatar: "https://..." },
{ label: "Nina Clark", value: "2", avatar: "https://..." },
];
<Select items={items} value={value} onValueChange={setValue}>
<SelectTrigger>
<SelectValue>
{(value: string | null) => {
const selectedItem = items.find((item) => item.value === value);
return selectedItem ? (
<span className="flex items-center gap-2">
<Avatar src={selectedItem.avatar} />
<span>{selectedItem.label}</span>
</span>
) : (
<span>Select a user</span>
);
}}
</SelectValue>
</SelectTrigger>
<SelectContent>
{items.map((item) => (
<SelectItem key={item.value} value={item.value}>
<span className="flex items-center gap-2">
<Avatar src={item.avatar} />
<span>{item.label}</span>
</span>
</SelectItem>
))}
</SelectContent>
</Select>;Using Cubitt's URL-state hooks, you can sync the select value with the URL by providing a paramName. The component automatically handles array serialization for multi-select mode.
// Single select - synced with ?category=electronics
const categoryItems = [
{ label: "Electronics", value: "electronics" },
{ label: "Books", value: "books" },
{ label: "Clothing", value: "clothing" },
];
<Select
items={categoryItems}
paramName="category"
defaultValue="electronics"
>
<SelectTrigger>
<SelectValue placeholder="Select category" />
</SelectTrigger>
<SelectContent>
{categoryItems.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</SelectContent>
</Select>
// Multi-select - synced with ?tags=react,typescript,ui (comma-separated)
const tagItems = [
{ label: "React", value: "react" },
{ label: "TypeScript", value: "typescript" },
{ label: "UI/UX", value: "ui" },
];
<Select
items={tagItems}
multiple
paramName="tags"
defaultValue={[]}
>
<SelectTrigger>
<SelectValue placeholder="Select tags" />
</SelectTrigger>
<SelectContent>
{tagItems.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</SelectContent>
</Select>
// Advanced options:
<Select
paramName="filter"
paramClearOnDefault={true} // Remove param when value equals default
paramDebounce={300} // Debounce URL updates
onUrlValueChange={(value) => console.log("Selected:", value)}
>
{/* ... */}
</Select>Examples
Indicator Position
Move the selection indicator to the left side.
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@tilt-legal/cubitt-components/primitives";
const items = [
{ label: "Apple", value: "apple" },
{ label: "Banana", value: "banana" },
{ label: "Cherry", value: "cherry" },
{ label: "Orange", value: "orange" },
{ label: "Grape", value: "grape" },
];
export default function Component() {
return (
<Select items={items} indicatorPosition="left">
<SelectTrigger className="w-60">
<SelectValue placeholder="Select a fruit" />
</SelectTrigger>
<SelectContent>
{items.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</SelectContent>
</Select>
);
}With Clear Button
Add a clear button to reset the selection.
import {
SelectClear,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@tilt-legal/cubitt-components/primitives";
import { useState } from "react";
import { Select } from "@tilt-legal/cubitt-components/primitives";
const items = [
{ label: "Apple", value: "apple" },
{ label: "Banana", value: "banana" },
{ label: "Cherry", value: "cherry" },
// ... more items
];
export default function Component() {
const [selectedValue, setSelectedValue] = useState<string | null>(null);
const handleClear = () => {
setSelectedValue(null);
};
const handleValueChange = (value: unknown) => {
setSelectedValue(value as string | null);
};
return (
<Select
items={items}
value={selectedValue}
onValueChange={handleValueChange}
>
<SelectTrigger className="w-60">
<SelectValue placeholder="Select a fruit" />
{selectedValue && <SelectClear onClick={handleClear} />}
</SelectTrigger>
<SelectContent>
{items.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</SelectContent>
</Select>
);
}With Groups
Organize related options into labeled groups with separators.
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectLabel,
SelectSeparator,
SelectTrigger,
SelectValue,
} from "@tilt-legal/cubitt-components/primitives";
export default function Component() {
return (
<Select>
<SelectTrigger className="w-60 relative">
<SelectValue>
{(value) => {
if (!value) return "Select framework...";
const item = frameworkItems.find((item) => item.value === value);
return item ? item.label : "Select framework...";
}}
</SelectValue>
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectLabel>Frontend</SelectLabel>
<SelectItem value="react">React</SelectItem>
<SelectItem value="nextjs">Next.js</SelectItem>
<SelectItem value="angular">Angular</SelectItem>
<SelectItem value="vue">Vue.js</SelectItem>
<SelectItem value="svelte">Svelte</SelectItem>
</SelectGroup>
<SelectSeparator />
<SelectGroup>
<SelectLabel>Backend</SelectLabel>
<SelectItem value="express">Express</SelectItem>
<SelectItem value="nestjs">NestJS</SelectItem>
<SelectItem value="django">Django</SelectItem>
<SelectItem value="flask">Flask</SelectItem>
<SelectItem value="laravel">Laravel</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
);
}Destructive Item
Use the destructive variant when one option represents a dangerous choice inside an otherwise standard select list.
import {
Select,
SelectContent,
SelectItem,
SelectSeparator,
SelectTrigger,
SelectValue,
} from "@tilt-legal/cubitt-components/primitives";
const items = [
{ label: "Rename workspace", value: "rename" },
{ label: "Duplicate workspace", value: "duplicate" },
{ label: "Delete workspace", value: "delete" },
];
export default function Component() {
return (
<Select items={items}>
<SelectTrigger className="w-60">
<SelectValue placeholder="Choose workspace action" />
</SelectTrigger>
<SelectContent>
<SelectItem value="rename">Rename workspace</SelectItem>
<SelectItem value="duplicate">Duplicate workspace</SelectItem>
<SelectSeparator />
<SelectItem value="delete" variant="destructive">
Delete workspace
</SelectItem>
</SelectContent>
</Select>
);
}Multiple Selection
Enable multi-select mode. Labels are automatically rendered from the items prop.
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@tilt-legal/cubitt-components/primitives";
const items = [
{ label: "Apple", value: "apple" },
{ label: "Banana", value: "banana" },
{ label: "Cherry", value: "cherry" },
// ... more items
];
export default function Component() {
return (
<Select items={items} defaultValue={["apple", "banana"]} multiple>
<SelectTrigger className="w-60">
<SelectValue placeholder="Select fruits" />
</SelectTrigger>
<SelectContent>
{items.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</SelectContent>
</Select>
);
}Size Variants
The select trigger supports three size variants: sm, md (default), and lg.
import {
SelectClear,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@tilt-legal/cubitt-components/primitives";
import { useState } from "react";
import { Select } from "@tilt-legal/cubitt-components/primitives";
const items = [
{ label: "Apple", value: "apple" },
{ label: "Banana", value: "banana" },
{ label: "Cherry", value: "cherry" },
// ... more items
];
export default function Component() {
const [smValue, setSmValue] = useState<string | null>(null);
const [mdValue, setMdValue] = useState<string | null>(null);
const [lgValue, setLgValue] = useState<string | null>(null);
return (
<div className="flex flex-col gap-6">
<Select
items={items}
value={smValue}
onValueChange={(value) => setSmValue(value as string | null)}
>
<SelectTrigger size="sm" className="w-60">
<SelectValue placeholder="Small" />
{smValue && <SelectClear onClick={() => setSmValue(null)} />}
</SelectTrigger>
<SelectContent>
{items.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</SelectContent>
</Select>
<Select
items={items}
value={mdValue}
onValueChange={(value) => setMdValue(value as string | null)}
>
<SelectTrigger className="w-60">
<SelectValue placeholder="Medium" />
{mdValue && <SelectClear onClick={() => setMdValue(null)} />}
</SelectTrigger>
<SelectContent>
{items.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</SelectContent>
</Select>
<Select
items={items}
value={lgValue}
onValueChange={(value) => setLgValue(value as string | null)}
>
<SelectTrigger size="lg" className="w-60">
<SelectValue placeholder="Large" />
{lgValue && <SelectClear onClick={() => setLgValue(null)} />}
</SelectTrigger>
<SelectContent>
{items.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
);
}Disabled States
Disable the entire select or specific items.
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@tilt-legal/cubitt-components/primitives";
const roleItems = [
{ label: "Developer", value: "developer" },
{ label: "Designer", value: "designer" },
{ label: "Manager", value: "manager" },
{ label: "QA Engineer", value: "qa" },
{ label: "Data Analyst", value: "data-analyst" },
];
export default function Component() {
return (
<div className="flex flex-col gap-6">
<Select items={roleItems} disabled>
<SelectTrigger className="w-60">
<SelectValue placeholder="Select a role" />
</SelectTrigger>
<SelectContent>
{roleItems.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</SelectContent>
</Select>
<Select items={roleItems}>
<SelectTrigger className="w-60">
<SelectValue placeholder="Select a role" />
</SelectTrigger>
<SelectContent>
<SelectItem value="developer">Developer</SelectItem>
<SelectItem value="designer" disabled>
Designer
</SelectItem>
<SelectItem value="manager">Manager</SelectItem>
<SelectItem value="qa" disabled>
QA Engineer
</SelectItem>
<SelectItem value="data-analyst">Data Analyst</SelectItem>
</SelectContent>
</Select>
</div>
);
}With Status Indicators
Display items with colored status dots.
import {
SelectClear,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@tilt-legal/cubitt-components/primitives";
import { cn } from "@tilt-legal/cubitt-components/utilities";
import { useState } from "react";
import { Select } from "@tilt-legal/cubitt-components/primitives";
const items = [
{ label: "In Progress", value: "1", state: "bg-violet-500" },
{ label: "Completed", value: "2", state: "bg-green-500" },
{ label: "Pending", value: "3", state: "bg-primary" },
{ label: "Cancelled", value: "4", state: "bg-yellow-500" },
{ label: "Rejected", value: "5", state: "bg-destructive" },
];
export default function Component() {
const [value, setValue] = useState<string | null>(null);
return (
<Select items={items} indicatorPosition="right">
<SelectTrigger className="w-60">
<SelectValue placeholder="Select status" />
{value && <SelectClear onClick={() => setValue(null)} />}
</SelectTrigger>
<SelectContent>
{items.map((item) => (
<SelectItem key={item.value} value={item.value}>
<span className="flex items-center gap-2">
<span className={cn("size-1.5 rounded-full", item.state)}></span>
<span>{item.label}</span>
</span>
</SelectItem>
))}
</SelectContent>
</Select>
);
}With Icons
Display items with custom icons.
import {
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@tilt-legal/cubitt-components/primitives";
import { useState } from "react";
import { Select } from "@tilt-legal/cubitt-components/primitives";
import {
SelectClear,
SelectContent,
SelectIndicator,
SelectItem,
SelectTrigger,
SelectValue,
} from "@tilt-legal/cubitt-components/primitives";
import {
RiGatsbyLine,
RiNextjsLine,
RiReactjsLine } from "@remixicon/react";
const frameworks = [
{ label: "React",
value: "react",
icon: RiReactjsLine },
{ label: "Next.js",
value: "nextjs",
icon: RiNextjsLine },
{ label: "Gatsby",
value: "gatsby",
icon: RiGatsbyLine },
];
export default function Component() {
const [value,
setValue] = useState<string | null>("gatsby");
const renderValue = (value: string | null) => {
const item = frameworks.find((i) => i.value === value);
if (!item) return "Select framework";
const Icon = item.icon;
return (
<span className="flex items-center gap-2">
<Icon className="size-4 opacity-60" />
<span>{item.label}</span>
</span>
);
};
return (
<Select
value={value}
onValueChange={(v) => setValue(v as string | null)}
indicatorPosition="right"
>
<SelectTrigger className="w-60">
<SelectValue>{renderValue}</SelectValue>
</SelectTrigger>
<SelectContent>
{frameworks.map((item) => {
const Icon = item.icon;
return (
<SelectItem key={item.value} value={item.value}>
<span className="flex items-center gap-2">
<Icon className="size-4 opacity-60" />
<span>{item.label}</span>
</span>
</SelectItem>
);
})}
</SelectContent>
</Select>
);
}With Descriptions
Display items with labels and descriptions, plus custom indicators.
import { useState } from "react";
import { Select } from "@tilt-legal/cubitt-components/primitives";
import {
AvatarFallback,
AvatarImage,
Select,
SelectClear,
SelectContent,
SelectGroup,
SelectItem,
SelectLabel,
SelectTrigger,
SelectValue,
} from "@tilt-legal/cubitt-components/primitives";
import {
RiCheckboxCircleFill } from "@remixicon/react";
const items = [
{
label: "Full access",
description: "Can modify list access",
value: "full_access",
},
{
label: "Read and write",
description: "Can edit & publish lists",
value: "read_write",
},
{
label: "Read only",
description: "Can only view lists",
value: "read_only",
},
{
label: "No access",
description: "Cannot view or edit lists",
value: "no_access",
},
];
export default function Component() {
const [value,
setValue] = useState<string | null>(null);
return (
<Select
items={items}
value={value}
onValueChange={(value) => setValue(value as string | null)}
indicatorPosition="right"
indicator={
<SelectIndicator>
<RiCheckboxCircleFill className="size-4 text-primary" />
</SelectIndicator>
}
>
<SelectTrigger className="w-60">
<SelectValue placeholder="Select access level" />
{value && <SelectClear onClick={() => setValue(null)} />}
</SelectTrigger>
<SelectContent>
{items.map((item) => (
<SelectItem key={item.value} value={item.value}>
<span className="flex flex-col items-start gap-px">
<span className="font-medium">{item.label}</span>
<small className="text-muted-foreground text-xs">
{item.description}
</small>
</span>
</SelectItem>
))}
</SelectContent>
</Select>
);
}With Avatars
Display items with user avatars.
import { useState } from "react";
import { Avatar } from "@tilt-legal/cubitt-components/primitives";
interface Item {
label: string;
avatar: string;
value: string;
}
const items: Item[] = [
{
label: "Alan Bold",
avatar: "https://randomuser.me/api/portraits/men/46.jpg",
value: "1",
},
{
label: "Ethan James",
avatar: "https://randomuser.me/api/portraits/men/29.jpg",
value: "2",
},
{
label: "Nina Clark",
avatar: "https://randomuser.me/api/portraits/men/10.jpg",
value: "3",
},
{
label: "Sean Otto",
avatar: "https://randomuser.me/api/portraits/men/12.jpg",
value: "4",
},
];
export default function Component() {
const [value, setValue] = useState<string | null>(null);
return (
<Select
value={value}
onValueChange={(value) => setValue(value as string | null)}
indicatorPosition="right"
>
<SelectTrigger className="w-60">
<SelectValue>
{(value: string | null) => {
const selectedItem = items.find((item) => item.value === value);
return selectedItem ? (
<span className="flex items-center gap-2">
<Avatar className="size-5">
<AvatarImage src={selectedItem.avatar} alt="@reui" />
<AvatarFallback>
{selectedItem.label.charAt(0)}
</AvatarFallback>
</Avatar>
<span>{selectedItem.label}</span>
</span>
) : (
<span>Select a user</span>
);
}}
</SelectValue>
{value && <SelectClear onClick={() => setValue(null)} />}
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectLabel className="text-xs py-1 font-normal text-muted-foreground ps-2">
Select a user
</SelectLabel>
{items.map((item) => (
<SelectItem key={item.value} value={item.value}>
<span className="flex items-center gap-2">
<Avatar className="size-6">
<AvatarImage src={item.avatar} alt="@reui" />
<AvatarFallback>{item.label.charAt(0)}</AvatarFallback>
</Avatar>
<span>{item.label}</span>
</span>
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
);
}With Badges
Display items as badge components for statuses.
import {
Select,
SelectClear,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@tilt-legal/cubitt-components/primitives";
import { useState } from "react";
import { Badge } from "@tilt-legal/cubitt-components/primitives";
const items = [
{ label: "In Progress", state: "primary", value: "1" },
{ label: "Completed", value: "2", state: "success" },
{ label: "Pending", value: "3", state: "info" },
{ label: "Cancelled", value: "4", state: "destructive" },
{ label: "Rejected", value: "5", state: "warning" },
];
export default function Component() {
const [value, setValue] = useState<string | null>(null);
return (
<Select
value={value}
onValueChange={(value) => setValue(value as string | null)}
indicatorPosition="right"
>
<SelectTrigger className="w-60">
<SelectValue>
{(value: string | null) => {
const selectedItem = items.find((item) => item.value === value);
return selectedItem ? (
<Badge
variant={selectedItem.state}
size="sm"
appearance="outline"
>
{selectedItem.label}
</Badge>
) : (
<span>Select a status</span>
);
}}
</SelectValue>
{value && <SelectClear onClick={() => setValue(null)} />}
</SelectTrigger>
<SelectContent>
{items.map((item) => (
<SelectItem key={item.value} value={item.value}>
<Badge variant={item.state} size="sm" appearance="outline">
{item.label}
</Badge>
</SelectItem>
))}
</SelectContent>
</Select>
);
}Scrollable Content
Handle long lists with scrollable content.
import {
SelectClear,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@tilt-legal/cubitt-components/primitives";
import { useState } from "react";
import { Select } from "@tilt-legal/cubitt-components/primitives";
export default function Component() {
const [value, setValue] = useState<string | null>(null);
const cities = [
{ label: "Tokyo", value: "tokyo" },
{ label: "New York", value: "new_york" },
{ label: "London", value: "london" },
// ... more cities
];
return (
<Select
items={cities}
value={value}
onValueChange={(value) => setValue(value as string | null)}
>
<SelectTrigger className="w-60">
<SelectValue placeholder="Select a city" />
{value && <SelectClear onClick={() => setValue(null)} />}
</SelectTrigger>
<SelectContent className="max-h-56">
{cities.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</SelectContent>
</Select>
);
}URL State (Single Select)
Sync a single selection with the URL. Try selecting a category and refreshing the page.
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@tilt-legal/cubitt-components/primitives";
const categories = [
{ label: "Electronics", value: "electronics" },
{ label: "Books", value: "books" },
{ label: "Clothing", value: "clothing" },
{ label: "Home & Garden", value: "home" },
{ label: "Sports", value: "sports" },
];
export default function Component() {
return (
<Select
items={categories}
paramName="demo-category"
defaultValue="electronics"
>
<SelectTrigger className="w-60">
<SelectValue placeholder="Select category..." />
</SelectTrigger>
<SelectContent>
{categories.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</SelectContent>
</Select>
);
}URL State (Multi-Select)
Sync multiple selections with the URL using comma-separated values.
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@tilt-legal/cubitt-components/primitives";
const tags = [
{ label: "React", value: "react" },
{ label: "TypeScript", value: "typescript" },
{ label: "Tailwind CSS", value: "tailwind" },
{ label: "Next.js", value: "nextjs" },
{ label: "Node.js", value: "nodejs" },
{ label: "UI/UX", value: "ui" },
];
export default function Component() {
return (
<Select items={tags} multiple paramName="demo-tags" defaultValue={[]}>
<SelectTrigger className="w-60">
<SelectValue placeholder="Select tags..." />
</SelectTrigger>
<SelectContent>
{tags.map((tag) => (
<SelectItem key={tag.value} value={tag.value}>
{tag.label}
</SelectItem>
))}
</SelectContent>
</Select>
);
}API Reference
Select
The root component that provides context for all child components.
| Prop | Type | Default | Description |
|---|---|---|---|
items | { label: ReactNode, value: string }[] | — | Label/value pairs used by the trigger display. Pass this whenever you want the default SelectValue to render labels instead of raw values. |
value | string | string[] | null | — | The controlled value of the select. |
defaultValue | string | string[] | null | — | The default value when uncontrolled. |
onValueChange | (value: string | string[] | null) => void | — | Callback when the selection changes. |
multiple | boolean | false | Enable multi-select mode. When true, value/defaultValue should be arrays. |
disabled | boolean | false | Disable the select component. |
readOnly | boolean | false | Make the select read-only (user cannot change selection). |
open | boolean | — | Control the open state of the dropdown. |
defaultOpen | boolean | false | The default open state when uncontrolled. |
onOpenChange | (open: boolean) => void | — | Callback when the open state changes. |
name | string | — | The name for form submission. |
required | boolean | false | Whether the select is required in forms. |
indicatorPosition | "left" | "right" | "right" | Position of the selection indicator within items. |
indicatorVisibility | boolean | true | Whether to show the selection indicator. |
indicator | ReactNode | — | Custom indicator component to replace the default checkmark. |
icon | ReactNode | — | Custom icon for the trigger button (replaces default chevron). |
invalid | boolean | false | Applies invalid styling and sets aria-invalid on the trigger. |
aria-invalid | AriaAttributes['aria-invalid'] | — | Forwarded to the trigger; values true, "grammar", or "spelling" are treated as invalid. |
aria-describedby | string | — | Forwarded to the trigger (useful for error message ids). |
className | string | — | Additional CSS classes for the select root. |
URL State Props
When provided with a paramName, the select will sync its value with URL parameters via TanStack Router search params.
| Prop | Type | Default | Description |
|---|---|---|---|
paramName | string | — | URL parameter name for syncing state with URL. Enables URL state management. |
onUrlValueChange | (value: string | string[] | null) => void | — | Callback when URL parameter value changes. |
paramClearOnDefault | boolean | true | Remove URL param when value equals default. |
paramThrottle | number | — | Throttle URL updates in milliseconds. |
paramDebounce | number | — | Debounce URL updates in milliseconds. |
SelectTrigger
The button that toggles the select dropdown.
| Prop | Type | Default | Description |
|---|---|---|---|
size | "sm" | "md" | "lg" | "md" | The size variant of the trigger. |
className | string | — | Additional CSS classes for the trigger. |
id | string | — | ID for linking with labels. |
SelectValue
Displays the selected value or placeholder text. When the items prop is provided on the Select root, labels are automatically rendered. For complex displays (icons, avatars, badges), provide a render function as children.
| Prop | Type | Default | Description |
|---|---|---|---|
placeholder | string | — | Text to display when no value is selected. |
className | string | — | Additional CSS classes for the value. |
children | ReactNode | ((value: string | string[] | null) => ReactNode) | — | Custom render function for complex displays. Receives the current value and should return React elements. |
SelectContent
The dropdown panel that contains the select options.
| Prop | Type | Description |
|---|---|---|
className | string | Additional CSS classes for the content. |
SelectItem
An individual option within the select dropdown.
| Prop | Type | Description |
|---|---|---|
value | string | The value this item represents. |
disabled | boolean | Whether the item is disabled. |
className | string | Additional CSS classes for the item. |
SelectGroup
Groups related select items together.
| Prop | Type | Description |
|---|---|---|
className | string | Additional CSS classes for the group. |
SelectLabel
A label for a group of select items.
| Prop | Type | Description |
|---|---|---|
className | string | Additional CSS classes for the label. |
SelectSeparator
A visual separator between groups or items.
| Prop | Type | Description |
|---|---|---|
className | string | Additional CSS classes for the separator. |
SelectClear
A button to clear the current selection. Must be positioned within the trigger.
| Prop | Type | Description |
|---|---|---|
onClick | () => void | Handler for clearing the selection. |
className | string | Additional CSS classes for the clear button. |
SelectIndicator
Custom indicator component to replace the default checkmark.
| Prop | Type | Description |
|---|---|---|
className | string | Additional CSS classes for the indicator. |
children | ReactNode | Custom indicator content. |