Select

Preview

import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectLabel,
SelectTrigger,
SelectValue,
} from "@/registry/components/select/react/select";
export function SelectDemo() {
return (
<Select>
<SelectTrigger style={{ "--select-trigger-width": "180px" } as any}>
<SelectValue placeholder="Select a fruit" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectLabel>Fruits</SelectLabel>
<SelectItem value="apple">Apple</SelectItem>
<SelectItem value="banana">Banana</SelectItem>
<SelectItem value="blueberry">Blueberry</SelectItem>
<SelectItem value="grapes">Grapes</SelectItem>
<SelectItem value="pineapple">Pineapple</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
);
}

Installation

You can add the dialog component in two ways:

  1. During project initialization:
pnpm dlx make-sugarcube@latest init
npx make-sugarcube@latest init
yarn make-sugarcube@latest init
bunx --bun make-sugarcube@latest init

Then select the dialog component when prompted.

  1. After initialization:
pnpm dlx make-sugarcube@latest components select --framework react
npx make-sugarcube@latest components select --framework react
yarn make-sugarcube@latest components select --framework react
bunx --bun make-sugarcube@latest components select --framework react

What’s included

When you add the label component, you get:

  • select.tsx - The React component implementation
  • select.tokens.json - The design tokens for the select component
  • @clsx - The clsx utility for conditional classes
"use client";
import * as SelectPrimitive from "@radix-ui/react-select";
import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react";
import type * as React from "react";
import cn from "clsx";
function Select({ ...props }: React.ComponentProps<typeof SelectPrimitive.Root>) {
return <SelectPrimitive.Root data-slot="select" {...props} />;
}
function SelectGroup({ ...props }: React.ComponentProps<typeof SelectPrimitive.Group>) {
return <SelectPrimitive.Group data-slot="select-group" {...props} />;
}
function SelectValue({ ...props }: React.ComponentProps<typeof SelectPrimitive.Value>) {
return <SelectPrimitive.Value data-slot="select-value" {...props} />;
}
function SelectTrigger({
className,
children,
...props
}: React.ComponentProps<typeof SelectPrimitive.Trigger>) {
return (
<SelectPrimitive.Trigger
data-slot="select-trigger"
className={cn("select-trigger", className)}
{...props}
>
{children}
<SelectPrimitive.Icon asChild>
<ChevronDownIcon />
</SelectPrimitive.Icon>
</SelectPrimitive.Trigger>
);
}
function SelectContent({
className,
children,
position = "popper",
...props
}: React.ComponentProps<typeof SelectPrimitive.Content>) {
return (
<SelectPrimitive.Portal>
<SelectPrimitive.Content
data-slot="select-content"
className={cn("select-content", className)}
position={position}
{...props}
>
<SelectScrollUpButton />
<SelectPrimitive.Viewport
className={cn(
"select-viewport",
position === "popper" && "select-viewport-popper"
)}
>
{children}
</SelectPrimitive.Viewport>
<SelectScrollDownButton />
</SelectPrimitive.Content>
</SelectPrimitive.Portal>
);
}
function SelectLabel({ className, ...props }: React.ComponentProps<typeof SelectPrimitive.Label>) {
return (
<SelectPrimitive.Label
data-slot="select-label"
className={cn("select-label", className)}
{...props}
/>
);
}
function SelectItem({
className,
children,
...props
}: React.ComponentProps<typeof SelectPrimitive.Item>) {
return (
<SelectPrimitive.Item
data-slot="select-item"
className={cn("select-item", className)}
{...props}
>
<span className="select-item-indicator">
<SelectPrimitive.ItemIndicator>
<CheckIcon />
</SelectPrimitive.ItemIndicator>
</span>
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
</SelectPrimitive.Item>
);
}
function SelectSeparator({
className,
...props
}: React.ComponentProps<typeof SelectPrimitive.Separator>) {
return (
<SelectPrimitive.Separator
data-slot="select-separator"
className={cn("select-separator", className)}
{...props}
/>
);
}
function SelectScrollUpButton({
className,
...props
}: React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>) {
return (
<SelectPrimitive.ScrollUpButton
data-slot="select-scroll-up-button"
className={cn("select-scroll-up-button", className)}
{...props}
>
<ChevronUpIcon />
</SelectPrimitive.ScrollUpButton>
);
}
function SelectScrollDownButton({
className,
...props
}: React.ComponentProps<typeof SelectPrimitive.ScrollDownButton>) {
return (
<SelectPrimitive.ScrollDownButton
data-slot="select-scroll-down-button"
className={cn("select-scroll-down-button", className)}
{...props}
>
<ChevronDownIcon />
</SelectPrimitive.ScrollDownButton>
);
}
export {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectLabel,
SelectScrollDownButton,
SelectScrollUpButton,
SelectSeparator,
SelectTrigger,
SelectValue,
};
.select-trigger {
display: flex;
white-space: nowrap;
align-items: center;
justify-content: space-between;
gap: 0.25rem;
width: var(--select-trigger-width, 100%);
border-radius: var(--select-trigger-radius);
border-style: var(--select-trigger-border-style);
border-width: var(--select-trigger-border-width);
border-color: var(--select-trigger-border-color);
background: var(--select-trigger-bg);
padding-block: var(--select-trigger-padding-block);
padding-inline: var(--select-trigger-padding-inline);
font-size: var(--select-trigger-size);
color: var(--select-trigger-fg);
height: var(--select-trigger-height);
}
.select-trigger > svg:not([data-slot="select-value"] svg) {
color: var(--text-muted);
opacity: 0.5;
}
.select-trigger > span[data-slot="select-value"] {
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
overflow: hidden;
line-clamp: 1;
display: flex;
align-items: center;
gap: 0.5rem;
}
.select-content {
position: relative;
z-index: 50;
overflow-x: hidden;
overflow-y: auto;
min-width: var(--select-content-min-width);
max-height: var(--radix-select-content-available-height);
border-radius: var(--select-content-radius);
border-style: var(--select-content-border-style);
border-width: var(--select-content-border-width);
border-color: var(--select-content-border-color);
background: var(--select-content-bg);
color: var(--select-content-fg);
box-shadow: var(--select-content-shadow);
}
.select-label {
color: var(--select-label-fg);
font-size: var(--select-label-size);
padding-inline: var(--select-label-padding-inline);
padding-block: var(--select-label-padding-block);
}
.select-item {
position: relative;
display: flex;
width: 100%;
cursor: default;
user-select: none;
align-items: center;
outline: none;
padding-inline: var(--select-item-padding-inline) 2rem;
padding-block: var(--select-item-padding-block);
font-size: var(--select-item-font-size);
}
.select-item > span:last-child {
display: flex;
align-items: center;
gap: 0.5rem;
}
.select-item[data-highlighted] {
outline: none;
background-color: var(--select-item-bg-highlighted);
border-radius: var(--select-item-radius);
}
.select-item[data-disabled] {
pointer-events: none;
color: var(--select-item-disabled);
}
.select-item-indicator {
color: var(--text-muted);
position: absolute;
right: 0.5rem;
display: flex;
align-items: center;
justify-content: center;
}
.select-viewport {
padding: var(--select-viewport-padding-block) var(--select-viewport-padding-inline);
height: var(--radix-select-trigger-height);
width: 100%;
min-width: var(--radix-select-trigger-width);
scroll-margin: 0.25rem;
}
.select-scroll-up-button,
.select-scroll-down-button {
display: flex;
align-items: center;
justify-content: center;
padding-block: var(--space-2xs);
}
.select-content[data-side="bottom"] {
transform: translateY(4px);
}
.select-content[data-side="top"] {
transform: translateY(-4px);
}
.select-content[data-side="left"] {
transform: translateX(-4px);
}
.select-content[data-side="right"] {
transform: translateX(4px);
}
.select-content[data-state="open"][data-side="bottom"] {
animation: select-slide-in-from-top var(--duration-150) var(--ease-out);
}
.select-content[data-state="open"][data-side="top"] {
animation: select-slide-in-from-bottom var(--duration-150) var(--ease-out);
}
.select-content[data-state="open"][data-side="left"] {
animation: select-slide-in-from-right var(--duration-150) var(--ease-out);
}
.select-content[data-state="open"][data-side="right"] {
animation: select-slide-in-from-left var(--duration-150) var(--ease-out);
}
@keyframes select-slide-in-from-top {
from {
opacity: 0;
transform: translateY(-8px) scale(0.95);
}
to {
opacity: 1;
transform: translateY(4px) scale(1);
}
}
@keyframes select-slide-in-from-bottom {
from {
opacity: 0;
transform: translateY(8px) scale(0.95);
}
to {
opacity: 1;
transform: translateY(-4px) scale(1);
}
}
@keyframes select-slide-in-from-left {
from {
opacity: 0;
transform: translateX(-8px) scale(0.95);
}
to {
opacity: 1;
transform: translateX(4px) scale(1);
}
}
@keyframes select-slide-in-from-right {
from {
opacity: 0;
transform: translateX(8px) scale(0.95);
}
to {
opacity: 1;
transform: translateX(-4px) scale(1);
}
}
{
"select": {
"trigger": {
"height": {
"$type": "dimension",
"$value": {
"value": 36,
"unit": "px"
}
},
"bg": {
"$value": "{color.transparent}"
},
"fg": {
"$value": "{color.text.primary}"
},
"radius": {
"$value": "{radius.input}"
},
"border": {
"style": {
"$value": "{input.stroke.style}"
},
"width": {
"$value": "{input.stroke.width}"
},
"color": {
"$value": "{input.stroke.color}"
}
},
"padding-block": {
"$value": "{input.padding.block}"
},
"padding-inline": {
"$value": "{input.padding.inline}"
},
"size": {
"$value": "{input.size}"
}
},
"content": {
"min-width": {
"$type": "dimension",
"$value": {
"value": 8,
"unit": "rem"
}
},
"radius": {
"$value": "{radius.panel}"
},
"border": {
"style": {
"$value": "{input.stroke.style}"
},
"width": {
"$value": "{input.stroke.width}"
},
"color": {
"$value": "{input.stroke.color}"
}
},
"bg": {
"$value": "{color.bg}"
},
"shadow": {
"$value": "{shadow.md}"
}
},
"label": {
"padding-block": {
"$type": "dimension",
"$value": {
"value": 0.375,
"unit": "rem"
}
},
"padding-inline": {
"$value": "{space.2xs}"
},
"fg": {
"$value": "{color.text.secondary}"
},
"size": {
"$value": "{text.xs}"
}
},
"item": {
"radius": {
"$value": "{radius.md}"
},
"font-size": {
"$value": "{input.size}"
},
"padding-block": {
"$type": "dimension",
"$value": {
"value": 0.375,
"unit": "rem"
}
},
"padding-inline": {
"$value": "{space.2xs}"
},
"bg-highlighted": {
"$value": "{color.bg-offset-1}"
}
},
"viewport": {
"padding-block": {
"$value": "{space.2xs}"
},
"padding-inline": {
"$value": "{space.3xs}"
}
}
}
}

Examples

:::note The following examples show how to use data attributes for variants. This is just one possible approach. See the principles section for more information on how to approach component variants. :::

Scrollable

import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectLabel,
SelectTrigger,
SelectValue,
} from "@/registry/components/select/react/select";
export function SelectScrollable() {
return (
<Select>
<SelectTrigger style={{ "--select-trigger-width": "280px" } as any}>
<SelectValue placeholder="Select a timezone" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectLabel>North America</SelectLabel>
<SelectItem value="est">Eastern Standard Time (EST)</SelectItem>
<SelectItem value="cst">Central Standard Time (CST)</SelectItem>
<SelectItem value="mst">Mountain Standard Time (MST)</SelectItem>
<SelectItem value="pst">Pacific Standard Time (PST)</SelectItem>
<SelectItem value="akst">Alaska Standard Time (AKST)</SelectItem>
<SelectItem value="hst">Hawaii Standard Time (HST)</SelectItem>
</SelectGroup>
<SelectGroup>
<SelectLabel>Europe & Africa</SelectLabel>
<SelectItem value="gmt">Greenwich Mean Time (GMT)</SelectItem>
<SelectItem value="cet">Central European Time (CET)</SelectItem>
<SelectItem value="eet">Eastern European Time (EET)</SelectItem>
<SelectItem value="west">Western European Summer Time (WEST)</SelectItem>
<SelectItem value="cat">Central Africa Time (CAT)</SelectItem>
<SelectItem value="eat">East Africa Time (EAT)</SelectItem>
</SelectGroup>
<SelectGroup>
<SelectLabel>Asia</SelectLabel>
<SelectItem value="msk">Moscow Time (MSK)</SelectItem>
<SelectItem value="ist">India Standard Time (IST)</SelectItem>
<SelectItem value="cst_china">China Standard Time (CST)</SelectItem>
<SelectItem value="jst">Japan Standard Time (JST)</SelectItem>
<SelectItem value="kst">Korea Standard Time (KST)</SelectItem>
<SelectItem value="ist_indonesia">
Indonesia Central Standard Time (WITA)
</SelectItem>
</SelectGroup>
<SelectGroup>
<SelectLabel>Australia & Pacific</SelectLabel>
<SelectItem value="awst">Australian Western Standard Time (AWST)</SelectItem>
<SelectItem value="acst">Australian Central Standard Time (ACST)</SelectItem>
<SelectItem value="aest">Australian Eastern Standard Time (AEST)</SelectItem>
<SelectItem value="nzst">New Zealand Standard Time (NZST)</SelectItem>
<SelectItem value="fjt">Fiji Time (FJT)</SelectItem>
</SelectGroup>
<SelectGroup>
<SelectLabel>South America</SelectLabel>
<SelectItem value="art">Argentina Time (ART)</SelectItem>
<SelectItem value="bot">Bolivia Time (BOT)</SelectItem>
<SelectItem value="brt">Brasilia Time (BRT)</SelectItem>
<SelectItem value="clt">Chile Standard Time (CLT)</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
);
}