- Accordion
- Alert
- Alert Dialog
- Autocomplete
- Avatar
- Badge
- Breadcrumb
- Button
- CalendarNew
- Card
- Checkbox
- Checkbox Group
- Collapsible
- Combobox
- Command
- Date PickerNew
- Dialog
- Empty
- Field
- Fieldset
- Form
- Frame
- Group
- Input
- Input Group
- Kbd
- Label
- Menu
- Meter
- Number Field
- Pagination
- Popover
- Preview Card
- Progress
- Radio Group
- Scroll Area
- Select
- Separator
- Sheet
- Skeleton
- Slider
- Spinner
- Switch
- Table
- Tabs
- Textarea
- Toast
- Toggle
- Toggle Group
- Toolbar
- Tooltip
Select
A common form component for choosing a predefined value in a dropdown menu.
import {
Select,
SelectItem,
SelectPopup,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
const items = [
{ label: "Select framework", value: null },
{ label: "Next.js", value: "next" },
{ label: "Vite", value: "vite" },
{ label: "Astro", value: "astro" },
];
export default function Particle() {
return (
<Select aria-label="Select framework" defaultValue="next" items={items}>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectPopup>
{items.map(({ label, value }) => (
<SelectItem key={value} value={value}>
{label}
</SelectItem>
))}
</SelectPopup>
</Select>
);
}
Installation
pnpm dlx shadcn@latest add @coss/select
Usage
import {
Select,
SelectItem,
SelectPopup,
SelectTrigger,
SelectValue,
} from "@/components/ui/select"const items = [
{ label: "Select framework", value: null },
{ label: "Next.js", value: "next" },
{ label: "Vite", value: "vite" },
{ label: "Astro", value: "astro" },
]
<Select items={items}>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectPopup>
{items.map((item) => (
<SelectItem key={item.value} value={item}>
{item.label}
</SelectItem>
))}
</SelectPopup>
</Select>API Reference
Select
Root component. Alias for Select.Root from Base UI.
SelectTrigger
Trigger button that opens the select dropdown. Styled wrapper for Select.Trigger from Base UI.
| Prop | Type | Default | Description |
|---|---|---|---|
size | "sm" | "default" | "lg" | "default" | Controls the size of the trigger |
SelectValue
Displays the selected value. Styled wrapper for Select.Value from Base UI.
SelectPopup
Popup container for select options. Also exported as SelectContent.
| Prop | Type | Default | Description |
|---|---|---|---|
alignItemWithTrigger | boolean | true | Aligns the selected item with the trigger |
sideOffset | number | 4 | Distance from the trigger in pixels |
SelectItem
Individual select option. Styled wrapper for Select.Item from Base UI with built-in indicator.
SelectGroup
Groups related select items. Alias for Select.Group from Base UI.
SelectGroupLabel
Label for a select group. Styled wrapper for Select.GroupLabel from Base UI.
SelectSeparator
Visual separator between items. Styled wrapper for Select.Separator from Base UI.
SelectButton
A standalone button styled like a SelectTrigger. Use it as a render prop on other trigger components (e.g., ComboboxTrigger, MenuTrigger) to give them select-like appearance.
| Prop | Type | Default | Description |
|---|---|---|---|
size | "sm" | "default" | "lg" | "default" | Controls the size of the button |
import { SelectButton } from "@/components/ui/select"<ComboboxTrigger render={<SelectButton />}>
<ComboboxValue placeholder="Select a fruit" />
</ComboboxTrigger>Examples
For accessible labelling and validation, prefer using the Field component to wrap selects. See the related example: Select field.
Small Size
import {
Select,
SelectItem,
SelectPopup,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
const items = [
{ label: "Select framework", value: null },
{ label: "Next.js", value: "next" },
{ label: "Vite", value: "vite" },
{ label: "Astro", value: "astro" },
];
export default function Particle() {
return (
<Select aria-label="Select framework" items={items}>
<SelectTrigger size="sm">
<SelectValue />
</SelectTrigger>
<SelectPopup>
{items.map(({ label, value }) => (
<SelectItem key={value} value={value}>
{label}
</SelectItem>
))}
</SelectPopup>
</Select>
);
}
Large Size
import {
Select,
SelectItem,
SelectPopup,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
const items = [
{ label: "Select framework", value: null },
{ label: "Next.js", value: "next" },
{ label: "Vite", value: "vite" },
{ label: "Astro", value: "astro" },
];
export default function Particle() {
return (
<Select aria-label="Select framework" items={items}>
<SelectTrigger size="lg">
<SelectValue />
</SelectTrigger>
<SelectPopup>
{items.map(({ label, value }) => (
<SelectItem key={value} value={value}>
{label}
</SelectItem>
))}
</SelectPopup>
</Select>
);
}
Disabled
import {
Select,
SelectItem,
SelectPopup,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
const items = [
{ label: "Select framework", value: null },
{ label: "Next.js", value: "next" },
{ label: "Vite", value: "vite" },
{ label: "Astro", value: "astro" },
];
export default function Particle() {
return (
<Select aria-label="Select framework" items={items}>
<SelectTrigger disabled>
<SelectValue />
</SelectTrigger>
<SelectPopup>
{items.map(({ label, value }) => (
<SelectItem key={value} value={value}>
{label}
</SelectItem>
))}
</SelectPopup>
</Select>
);
}
Without Item Alignment
import {
Select,
SelectItem,
SelectPopup,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
const items = [
{ label: "Select framework", value: null },
{ label: "Next.js", value: "next" },
{ label: "Vite", value: "vite" },
{ label: "Astro", value: "astro" },
];
export default function Particle() {
return (
<Select aria-label="Select framework" items={items}>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectPopup alignItemWithTrigger={false}>
{items.map(({ label, value }) => (
<SelectItem key={value} value={value}>
{label}
</SelectItem>
))}
</SelectPopup>
</Select>
);
}
With Groups
import {
Select,
SelectGroup,
SelectGroupLabel,
SelectItem,
SelectPopup,
SelectSeparator,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
const placeholder = [{ label: "Select framework", value: null }];
const frontend = [
{ label: "Next.js", value: "next" },
{ label: "Vite", value: "vite" },
{ label: "Astro", value: "astro" },
];
const backend = [
{ label: "Express", value: "express" },
{ label: "NestJS", value: "nestjs" },
{ label: "Fastify", value: "fastify" },
{ label: "Django", value: "django" },
{ label: "Flask", value: "flask" },
{ label: "Rails", value: "rails" },
];
export default function Particle() {
return (
<Select
aria-label="Select framework"
items={[...placeholder, ...frontend, ...backend]}
>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectPopup>
<SelectGroup>
<SelectGroupLabel>Frontend</SelectGroupLabel>
{frontend.map(({ label, value }) => (
<SelectItem key={value} value={value}>
{label}
</SelectItem>
))}
</SelectGroup>
<SelectSeparator />
<SelectGroup>
<SelectGroupLabel>Backend</SelectGroupLabel>
{backend.map(({ label, value }) => (
<SelectItem key={value} value={value}>
{label}
</SelectItem>
))}
</SelectGroup>
</SelectPopup>
</Select>
);
}
Multiple Selection
"use client";
import {
Select,
SelectItem,
SelectPopup,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
const languages = {
cpp: "C++",
csharp: "C#",
go: "Go",
java: "Java",
javascript: "JavaScript",
php: "PHP",
python: "Python",
rust: "Rust",
swift: "Swift",
typescript: "TypeScript",
};
type Language = keyof typeof languages;
const values = Object.keys(languages) as Language[];
function renderValue(value: Language[]) {
if (value.length === 0) {
return "Select languages…";
}
const firstLanguage = value[0] ? languages[value[0]] : "";
const additionalLanguages =
value.length > 1 ? ` (+${value.length - 1} more)` : "";
return firstLanguage + additionalLanguages;
}
export default function Particle() {
return (
<Select
aria-label="Select languages"
defaultValue={["javascript", "typescript"]}
multiple
>
<SelectTrigger>
<SelectValue>{renderValue}</SelectValue>
</SelectTrigger>
<SelectPopup alignItemWithTrigger={false}>
{values.map((value) => (
<SelectItem key={value} value={value}>
{languages[value]}
</SelectItem>
))}
</SelectPopup>
</Select>
);
}
With Icon
import { CableIcon } from "lucide-react";
import {
Select,
SelectItem,
SelectPopup,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
const items = [
{ label: "Select framework", value: null },
{ label: "Next.js", value: "next" },
{ label: "Vite", value: "vite" },
{ label: "Astro", value: "astro" },
];
export default function Particle() {
return (
<Select
aria-label="Select framework with icon"
defaultValue="next"
items={items}
>
<SelectTrigger>
<CableIcon aria-hidden="true" />
<SelectValue />
</SelectTrigger>
<SelectPopup alignItemWithTrigger={false}>
{items.map(({ label, value }) => (
<SelectItem key={value} value={value}>
{label}
</SelectItem>
))}
</SelectPopup>
</Select>
);
}
Options with Icon
"use client";
import { Code2Icon, GlobeIcon, LayersIcon, ZapIcon } from "lucide-react";
import {
Select,
SelectItem,
SelectPopup,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
const items = [
{ icon: LayersIcon, label: "Components", value: "components" },
{ icon: ZapIcon, label: "Performance", value: "performance" },
{ icon: GlobeIcon, label: "Network", value: "network" },
{ icon: Code2Icon, label: "Development", value: "development" },
];
export default function Particle() {
return (
<Select
aria-label="Select category"
defaultValue={items[0]}
itemToStringValue={(item) => item.value}
>
<SelectTrigger>
<SelectValue>
{(item) => (
<span className="flex items-center gap-2">
<item.icon />
<span className="truncate">{item.label}</span>
</span>
)}
</SelectValue>
</SelectTrigger>
<SelectPopup>
{items.map((item) => (
<SelectItem key={item.value} value={item}>
<span className="flex items-center gap-2">
<item.icon />
<span className="truncate">{item.label}</span>
</span>
</SelectItem>
))}
</SelectPopup>
</Select>
);
}
With Object Values
"use client";
import {
Select,
SelectItem,
SelectPopup,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
const items = [
{ description: "npx create-next-app", label: "Next.js", value: "next" },
{ description: "npm create vite@latest", label: "Vite", value: "vite" },
{ description: "npm create astro@latest", label: "Astro", value: "astro" },
{ description: "npx create-remix", label: "Remix", value: "remix" },
];
export default function Particle() {
return (
<Select
aria-label="Select framework with command"
defaultValue={items[0]}
itemToStringValue={(item) => item.value}
>
<SelectTrigger className="py-1">
<SelectValue>
{(item) => (
<span className="flex flex-col">
<span className="truncate">{item.label}</span>
<span className="truncate text-muted-foreground text-xs">
{item.description}
</span>
</span>
)}
</SelectValue>
</SelectTrigger>
<SelectPopup>
{items.map((item) => (
<SelectItem key={item.value} value={item}>
<span className="flex flex-col">
<span className="truncate">{item.label}</span>
<span className="truncate text-muted-foreground text-xs">
{item.description}
</span>
</span>
</SelectItem>
))}
</SelectPopup>
</Select>
);
}
SelectButton with Combobox
Use SelectButton as a render prop on ComboboxTrigger to create a combobox that looks like a select.
"use client";
import { SearchIcon } from "lucide-react";
import {
Combobox,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxList,
ComboboxPopup,
ComboboxTrigger,
ComboboxValue,
} from "@/components/ui/combobox";
import { SelectButton } from "@/components/ui/select";
const items = [
{ label: "Apple", value: "apple" },
{ label: "Banana", value: "banana" },
{ label: "Orange", value: "orange" },
{ label: "Grape", value: "grape" },
{ label: "Strawberry", value: "strawberry" },
{ label: "Mango", value: "mango" },
{ label: "Pineapple", value: "pineapple" },
{ label: "Kiwi", value: "kiwi" },
{ label: "Peach", value: "peach" },
{ label: "Pear", value: "pear" },
];
export default function Particle() {
return (
<Combobox items={items}>
<ComboboxTrigger render={<SelectButton />}>
<ComboboxValue placeholder="Select a fruit" />
</ComboboxTrigger>
<ComboboxPopup aria-label="Select a fruit">
<div className="border-b p-2">
<ComboboxInput
className="rounded-md before:rounded-[calc(var(--radius-md)-1px)]"
placeholder="Search fruits..."
showTrigger={false}
startAddon={<SearchIcon />}
/>
</div>
<ComboboxEmpty>No items found.</ComboboxEmpty>
<ComboboxList>
{(item) => (
<ComboboxItem key={item.value} value={item}>
{item.label}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxPopup>
</Combobox>
);
}
Form Integration
"use client";
import type { FormEvent } from "react";
import { useState } from "react";
import { Button } from "@/components/ui/button";
import {
Field,
FieldDescription,
FieldError,
FieldLabel,
} from "@/components/ui/field";
import { Form } from "@/components/ui/form";
import {
Select,
SelectItem,
SelectPopup,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
const items = [
{ label: "Select a framework", value: null },
{ label: "Next.js", value: "next" },
{ label: "Vite", value: "vite" },
{ label: "Astro", value: "astro" },
];
export default function Particle() {
const [loading, setLoading] = useState(false);
const onSubmit = async (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
const formData = new FormData(e.currentTarget);
setLoading(true);
await new Promise((r) => setTimeout(r, 800));
setLoading(false);
alert(`Framework: ${formData.get("framework") || ""}`);
};
return (
<Form className="max-w-64" onSubmit={onSubmit}>
<Field>
<FieldLabel>Framework</FieldLabel>
<Select
aria-label="Select framework"
disabled={loading}
items={items}
name="framework"
required
>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectPopup>
{items.map(({ label, value }) => (
<SelectItem key={value} value={value}>
{label}
</SelectItem>
))}
</SelectPopup>
</Select>
<FieldDescription>Pick your favorite.</FieldDescription>
<FieldError>Please select a value.</FieldError>
</Field>
<Button disabled={loading} type="submit">
Submit
</Button>
</Form>
);
}
On This Page