Github

Select

Displays a list of options for the user to pick from—triggered by a button.

import {	Select,	SelectContent,	SelectGroup,	SelectItem,	SelectTrigger,	SelectValue,} from "@/components/ui/select";
const items = [	{ label: "Select a fruit", value: null },	{ label: "Apple", value: "apple" },	{ label: "Banana", value: "banana" },	{ label: "Blueberry", value: "blueberry" },];
export function SelectDemo() {	return (		<Select items={items}>			<SelectTrigger className="w-full max-w-48">				<SelectValue />			</SelectTrigger>			<SelectContent>				<SelectGroup>					{items.map((item) => (						<SelectItem key={item.label} value={item.value}>							{item.label}						</SelectItem>					))}				</SelectGroup>			</SelectContent>		</Select>	);}

Installation

pnpm dlx shadcn@latest add @herocn/select

Usage

import {  Select,  SelectContent,  SelectGroup,  SelectItem,  SelectLabel,  SelectSeparator,  SelectTrigger,  SelectValue,} from "@/components/ui/select"

Pass an items array to Select so SelectValue can show the label for the selected option. Render SelectItem children for each option (including groups and separators as needed).

const items = [  { label: "Select a fruit", value: null },  { label: "Apple", value: "apple" },  { label: "Banana", value: "banana" },]
<Select items={items}>  <SelectTrigger className="w-full max-w-48">    <SelectValue />  </SelectTrigger>  <SelectContent>    <SelectGroup>      {items.map((item) => (        <SelectItem key={item.label} value={item.value}>          {item.label}        </SelectItem>      ))}    </SelectGroup>  </SelectContent></Select>

Composition

Use the following composition to build a Select:

Select├── SelectTrigger│   └── SelectValue└── SelectContent    ├── SelectGroup    │   ├── SelectLabel    │   ├── SelectItem    │   └── SelectItem    ├── SelectSeparator    └── SelectGroup        ├── SelectLabel        ├── SelectItem        └── SelectItem

Examples

Groups

Use SelectGroup, SelectLabel, and SelectSeparator to organize items.

import {	Select,	SelectContent,	SelectGroup,	SelectItem,	SelectLabel,	SelectSeparator,	SelectTrigger,	SelectValue,} from "@/components/ui/select";
export function SelectGroups() {	const fruits = [		{ label: "Apple", value: "apple" },		{ label: "Banana", value: "banana" },		{ label: "Blueberry", value: "blueberry" },	];	const vegetables = [		{ label: "Carrot", value: "carrot" },		{ label: "Broccoli", value: "broccoli" },		{ label: "Spinach", value: "spinach" },	];	const allItems = [		{ label: "Select a fruit", value: null },		...fruits,		...vegetables,	];	return (		<Select items={allItems}>			<SelectTrigger className="w-full max-w-48">				<SelectValue />			</SelectTrigger>			<SelectContent>				<SelectGroup>					<SelectLabel>Fruits</SelectLabel>					{fruits.map((item) => (						<SelectItem key={item.value} value={item.value}>							{item.label}						</SelectItem>					))}				</SelectGroup>				<SelectSeparator />				<SelectGroup>					<SelectLabel>Vegetables</SelectLabel>					{vegetables.map((item) => (						<SelectItem key={item.value} value={item.value}>							{item.label}						</SelectItem>					))}				</SelectGroup>			</SelectContent>		</Select>	);}

Multiple

Set multiple on Select and control selection with an array value and onValueChange.

"use client";
import * as React from "react";import {	Select,	SelectContent,	SelectGroup,	SelectItem,	SelectTrigger,	SelectValue,} from "@/components/ui/select";
const fruits = [	{ label: "Apple", value: "apple" },	{ label: "Banana", value: "banana" },	{ label: "Blueberry", value: "blueberry" },	{ label: "Grapes", value: "grapes" },	{ label: "Pineapple", value: "pineapple" },];
export function SelectMultiple() {	const [value, setValue] = React.useState<string[]>([]);
	return (		<Select multiple items={fruits} value={value} onValueChange={setValue}>			<SelectTrigger className="w-full max-w-sm">				<SelectValue placeholder="Select fruits..." />			</SelectTrigger>			<SelectContent>				<SelectGroup>					{fruits.map((item) => (						<SelectItem key={item.value} value={item.value}>							{item.label}						</SelectItem>					))}				</SelectGroup>			</SelectContent>		</Select>	);}

Scrollable

A select with many items scrolls inside the popup.

import {	Select,	SelectContent,	SelectGroup,	SelectItem,	SelectLabel,	SelectTrigger,	SelectValue,} from "@/components/ui/select";
const northAmerica = [	{ label: "Eastern Standard Time", value: "est" },	{ label: "Central Standard Time", value: "cst" },	{ label: "Mountain Standard Time", value: "mst" },	{ label: "Pacific Standard Time", value: "pst" },	{ label: "Alaska Standard Time", value: "akst" },	{ label: "Hawaii Standard Time", value: "hst" },];
const europeAfrica = [	{ label: "Greenwich Mean Time", value: "gmt" },	{ label: "Central European Time", value: "cet" },	{ label: "Eastern European Time", value: "eet" },	{ label: "Western European Summer Time", value: "west" },	{ label: "Central Africa Time", value: "cat" },	{ label: "East Africa Time", value: "eat" },];
const asia = [	{ label: "Moscow Time", value: "msk" },	{ label: "India Standard Time", value: "ist" },	{ label: "China Standard Time", value: "cst_china" },	{ label: "Japan Standard Time", value: "jst" },	{ label: "Korea Standard Time", value: "kst" },	{ label: "Indonesia Central Standard Time", value: "ist_indonesia" },];
const australiaPacific = [	{ label: "Australian Western Standard Time", value: "awst" },	{ label: "Australian Central Standard Time", value: "acst" },	{ label: "Australian Eastern Standard Time", value: "aest" },	{ label: "New Zealand Standard Time", value: "nzst" },	{ label: "Fiji Time", value: "fjt" },];
const southAmerica = [	{ label: "Argentina Time", value: "art" },	{ label: "Bolivia Time", value: "bot" },	{ label: "Brasilia Time", value: "brt" },	{ label: "Chile Standard Time", value: "clt" },];
const items = [	{ label: "Select a timezone", value: null },	...northAmerica,	...europeAfrica,	...asia,	...australiaPacific,	...southAmerica,];
export function SelectScrollable() {	return (		<Select items={items}>			<SelectTrigger className="w-full max-w-64">				<SelectValue />			</SelectTrigger>			<SelectContent>				<SelectGroup>					<SelectLabel>North America</SelectLabel>					{northAmerica.map((item) => (						<SelectItem key={item.value} value={item.value}>							{item.label}						</SelectItem>					))}				</SelectGroup>				<SelectGroup>					<SelectLabel>Europe & Africa</SelectLabel>					{europeAfrica.map((item) => (						<SelectItem key={item.value} value={item.value}>							{item.label}						</SelectItem>					))}				</SelectGroup>				<SelectGroup>					<SelectLabel>Asia</SelectLabel>					{asia.map((item) => (						<SelectItem key={item.value} value={item.value}>							{item.label}						</SelectItem>					))}				</SelectGroup>				<SelectGroup>					<SelectLabel>Australia & Pacific</SelectLabel>					{australiaPacific.map((item) => (						<SelectItem key={item.value} value={item.value}>							{item.label}						</SelectItem>					))}				</SelectGroup>				<SelectGroup>					<SelectLabel>South America</SelectLabel>					{southAmerica.map((item) => (						<SelectItem key={item.value} value={item.value}>							{item.label}						</SelectItem>					))}				</SelectGroup>			</SelectContent>		</Select>	);}

Disabled

Set disabled on the root Select to disable the whole control, or on individual SelectItem components to disable specific options.

import {	Select,	SelectContent,	SelectGroup,	SelectItem,	SelectTrigger,	SelectValue,} from "@/components/ui/select";
const items: Array<{	label: string;	value: string | null;	disabled?: boolean;}> = [	{ label: "Select a fruit", value: null },	{ label: "Apple", value: "apple" },	{ label: "Banana", value: "banana" },	{ label: "Blueberry", value: "blueberry" },	{ label: "Grapes", value: "grapes", disabled: true },	{ label: "Pineapple", value: "pineapple" },];
export function SelectDisabled() {	return (		<Select items={items} disabled>			<SelectTrigger className="w-full max-w-48">				<SelectValue />			</SelectTrigger>			<SelectContent>				<SelectGroup>					{items.map((item) => (						<SelectItem							key={item.label}							value={item.value}							disabled={item.disabled}						>							{item.label}						</SelectItem>					))}				</SelectGroup>			</SelectContent>		</Select>	);}

Invalid

Add the data-invalid attribute to the Field component and the aria-invalid attribute to the SelectTrigger component to show an error state.

<Field data-invalid>  <FieldLabel>Fruit</FieldLabel>  <SelectTrigger aria-invalid>    <SelectValue />  </SelectTrigger></Field>
import { Field, FieldError, FieldLabel } from "@/components/ui/field";import {	Select,	SelectContent,	SelectGroup,	SelectItem,	SelectTrigger,	SelectValue,} from "@/components/ui/select";
const items = [	{ label: "Select a fruit", value: null },	{ label: "Apple", value: "apple" },	{ label: "Banana", value: "banana" },	{ label: "Blueberry", value: "blueberry" },];
export function SelectInvalid() {	return (		<Field data-invalid className="w-full max-w-48">			<FieldLabel>Fruit</FieldLabel>			<Select items={items}>				<SelectTrigger aria-invalid>					<SelectValue />				</SelectTrigger>				<SelectContent>					<SelectGroup>						{items.map((item) => (							<SelectItem key={item.label} value={item.value}>								{item.label}							</SelectItem>						))}					</SelectGroup>				</SelectContent>			</Select>			<FieldError>Please select a fruit.</FieldError>		</Field>	);}

Variants

The Select component supports two visual variants:

  • primary (default) - Standard styling with shadow, suitable for most use cases
  • secondary - Lower emphasis variant without shadow, suitable for use in Surface components
import {	Select,	SelectContent,	SelectGroup,	SelectItem,	SelectTrigger,	SelectValue,} from "@/components/ui/select";
const items = [	{ label: "Select a fruit", value: null },	{ label: "Apple", value: "apple" },	{ label: "Banana", value: "banana" },	{ label: "Blueberry", value: "blueberry" },];
export function SelectVariants() {	return (		<div className="flex w-full max-w-sm flex-col gap-4">			<Select items={items} variant="default">				<SelectTrigger className="w-full">					<SelectValue />				</SelectTrigger>				<SelectContent>					<SelectGroup>						{items.map((item) => (							<SelectItem key={item.label} value={item.value}>								{item.label}							</SelectItem>						))}					</SelectGroup>				</SelectContent>			</Select>			<Select items={items} variant="secondary">				<SelectTrigger className="w-full">					<SelectValue />				</SelectTrigger>				<SelectContent>					<SelectGroup>						{items.map((item) => (							<SelectItem key={item.label} value={item.value}>								{item.label}							</SelectItem>						))}					</SelectGroup>				</SelectContent>			</Select>		</div>	);}

In Surface

Place the select inside a Surface panel. Use variant="secondary" on Select so the trigger sits cleanly on the surface background.

Appearance

Choose how the interface looks on this device.

import {	Select,	SelectContent,	SelectGroup,	SelectItem,	SelectTrigger,	SelectValue,} from "@/components/ui/select";import { Surface } from "@/components/ui/surface";
const items = [	{ label: "Select a theme", value: null },	{ label: "Light", value: "light" },	{ label: "Dark", value: "dark" },	{ label: "System", value: "system" },];
export function SelectSurface() {	return (		<Surface className="w-full max-w-sm rounded-3xl border p-4">			<h4 className="font-medium text-sm">Appearance</h4>			<p className="mt-1 text-muted-foreground text-sm">				Choose how the interface looks on this device.			</p>			<div className="mt-4">				<Select items={items} variant="secondary">					<SelectTrigger className="w-full">						<SelectValue />					</SelectTrigger>					<SelectContent>						<SelectGroup>							{items.map((item) => (								<SelectItem key={item.label} value={item.value}>									{item.label}								</SelectItem>							))}						</SelectGroup>					</SelectContent>				</Select>			</div>		</Surface>	);}

RTL

To enable RTL support in shadcn/ui, see the RTL configuration guide.

"use client";
import * as React from "react";
import {	type Translations,	useTranslation,} from "@/components/language-selector";import {	Select,	SelectContent,	SelectGroup,	SelectItem,	SelectLabel,	SelectSeparator,	SelectTrigger,	SelectValue,} from "@/components/ui/select";
const translations: Translations = {	en: {		dir: "ltr",		values: {			selectFruit: "Select a fruit",			fruits: "Fruits",			apple: "Apple",			banana: "Banana",			blueberry: "Blueberry",			grapes: "Grapes",			pineapple: "Pineapple",			vegetables: "Vegetables",			carrot: "Carrot",			broccoli: "Broccoli",			spinach: "Spinach",		},	},	ar: {		dir: "rtl",		values: {			selectFruit: "اختر فاكهة",			fruits: "الفواكه",			apple: "تفاح",			banana: "موز",			blueberry: "توت أزرق",			grapes: "عنب",			pineapple: "أناناس",			vegetables: "الخضروات",			carrot: "جزر",			broccoli: "بروكلي",			spinach: "سبانخ",		},	},	he: {		dir: "rtl",		values: {			selectFruit: "בחר פרי",			fruits: "פירות",			apple: "תפוח",			banana: "בננה",			blueberry: "אוכמניה",			grapes: "ענבים",			pineapple: "אננס",			vegetables: "ירקות",			carrot: "גזר",			broccoli: "ברוקולי",			spinach: "תרד",		},	},};
export function SelectRtl() {	const { dir, t, language } = useTranslation(translations, "ar");	const [selectedFruit, setSelectedFruit] = React.useState<string | null>(null);
	const fruits = [		{ label: t.apple, value: "apple" },		{ label: t.banana, value: "banana" },		{ label: t.blueberry, value: "blueberry" },		{ label: t.grapes, value: "grapes" },		{ label: t.pineapple, value: "pineapple" },	];
	const vegetables = [		{ label: t.carrot, value: "carrot" },		{ label: t.broccoli, value: "broccoli" },		{ label: t.spinach, value: "spinach" },	];
	const allItems = [		{ label: t.selectFruit, value: null },		...fruits,		...vegetables,	];
	return (		<Select			items={allItems}			value={selectedFruit}			data-lang={language}			onValueChange={setSelectedFruit}		>			<SelectTrigger				data-lang={dir === "rtl" ? language : undefined}				className="w-auto min-w-32"				dir={dir}			>				<SelectValue />			</SelectTrigger>			<SelectContent dir={dir} data-lang={dir === "rtl" ? language : undefined}>				<SelectGroup>					<SelectLabel>{t.fruits}</SelectLabel>					{fruits.map((item) => (						<SelectItem key={item.value} value={item.value}>							{item.label}						</SelectItem>					))}				</SelectGroup>				<SelectSeparator />				<SelectGroup>					<SelectLabel>{t.vegetables}</SelectLabel>					{vegetables.map((item) => (						<SelectItem key={item.value} value={item.value}>							{item.label}						</SelectItem>					))}				</SelectGroup>			</SelectContent>		</Select>	);}

API Reference

The select is built on Base UI Select. Select forwards props to the root; SelectTrigger adds styling and a size option.

Select

PropTypeDefault

See the Base UI Select API reference for all other props (items, value, onValueChange, positioning, etc.).