Theme
Installation
CLI
npx shadcn@latest add "https://eo-n.vercel.app/r/select"
Manual
Copy and paste the following code into your project.
"use client";
import * as React from "react";
import { Select as SelectPrimitive } from "@base-ui-components/react/select";
import {
Check,
ChevronDownIcon,
ChevronsUpDown,
ChevronUpIcon,
} from "lucide-react";
import { cn } from "@/lib/utils";
function Select({
alignItemToTrigger = false,
...props
}: React.ComponentProps<typeof SelectPrimitive.Root>) {
return (
<SelectPrimitive.Root
data-slot="select"
alignItemToTrigger={alignItemToTrigger}
{...props}
/>
);
}
interface SelectTriggerProps
extends React.ComponentProps<typeof SelectPrimitive.Trigger> {
size?: "sm" | "default";
}
function SelectTrigger({
className,
size = "default",
children,
...props
}: SelectTriggerProps) {
return (
<SelectPrimitive.Trigger
data-slot="select-trigger"
data-size={size}
className={cn(
"border-input ring-offset-background [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 dark:hover:bg-input/50 flex w-fit cursor-pointer items-center justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
className
)}
{...props}
>
{children}
<SelectPrimitive.Icon>
<ChevronsUpDown className="size-4 opacity-50" />
</SelectPrimitive.Icon>
</SelectPrimitive.Trigger>
);
}
function SelectValue({
className,
...props
}: React.ComponentProps<typeof SelectPrimitive.Value>) {
return (
<SelectPrimitive.Value
data-slot="select-value"
className={cn("w-full overflow-hidden text-ellipsis", className)}
{...props}
/>
);
}
function SelectBackdrop({
...props
}: React.ComponentProps<typeof SelectPrimitive.Backdrop>) {
return <SelectPrimitive.Backdrop data-slot="select-backdrop" {...props} />;
}
function SelectPortal({
...props
}: React.ComponentProps<typeof SelectPrimitive.Portal>) {
return <SelectPrimitive.Portal data-slot="select-portal" {...props} />;
}
interface SelectContentProps
extends Omit<
React.ComponentProps<typeof SelectPrimitive.Positioner>,
"render"
> {}
function SelectContent({
className,
sideOffset = 4,
children,
...props
}: SelectContentProps) {
return (
<SelectPortal>
<SelectBackdrop />
<SelectPrimitive.Positioner
data-slot="select-positioner"
sideOffset={sideOffset}
className="relative z-50 size-auto"
{...props}
>
<SelectPrimitive.ScrollUpArrow
data-slot="select-scroll-up-arrow"
className="top-0 z-[1] flex w-full cursor-default items-center justify-center py-1"
>
<ChevronUpIcon className="size-4" />
</SelectPrimitive.ScrollUpArrow>
<SelectPrimitive.Popup
data-slot="select-content"
className={cn(
"bg-popover text-popover-foreground max-h-[var(--available-height)] max-w-[var(--available-width)] w-[var(--anchor-width)] overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md transition-[transform,scale,opacity] duration-150 ease-out",
"origin-[var(--transform-origin)] data-[ending-style]:scale-95 data-[ending-style]:opacity-0 data-[side=none]:data-[ending-style]:scale-100 data-[side=none]:data-[ending-style]:opacity-0 data-[side=none]:data-[ending-style]:transition-none data-[starting-style]:scale-95 data-[starting-style]:opacity-0 data-[side=none]:data-[starting-style]:scale-100 data-[side=none]:data-[starting-style]:opacity-0",
className
)}
>
{children}
</SelectPrimitive.Popup>
<SelectPrimitive.ScrollDownArrow
data-slot="select-scroll-down-arrow"
className="bottom-0 z-[1] flex w-full cursor-default items-center justify-center py-1"
>
<ChevronDownIcon className="size-4" />
</SelectPrimitive.ScrollDownArrow>
</SelectPrimitive.Positioner>
</SelectPortal>
);
}
function SelectItem({
className,
children,
...props
}: React.ComponentProps<typeof SelectPrimitive.Item>) {
return (
<SelectPrimitive.Item
data-slot="select-item"
className={cn(
"data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
className
)}
{...props}
>
<span className="absolute right-2 flex size-3.5 items-center justify-center">
<SelectPrimitive.ItemIndicator>
<Check className="size-4" />
</SelectPrimitive.ItemIndicator>
</span>
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
</SelectPrimitive.Item>
);
}
function SelectGroup({
...props
}: React.ComponentProps<typeof SelectPrimitive.Group>) {
return <SelectPrimitive.Group data-slot="select-group" {...props} />;
}
function SelectGroupLabel({
className,
...props
}: React.ComponentProps<typeof SelectPrimitive.GroupLabel>) {
return (
<SelectPrimitive.Group
data-slot="select-group-label"
className={cn("text-muted-foreground px-2 py-1.5 text-xs", className)}
{...props}
/>
);
}
function SelectScrollUpArrow({
className,
...props
}: React.ComponentProps<typeof SelectPrimitive.ScrollUpArrow>) {
return (
<SelectPrimitive.ScrollUpArrow
data-slot="select-scroll-up-arrow"
className={cn(
"top-0 z-[1] flex w-full cursor-default items-center justify-center py-2",
className
)}
{...props}
>
<ChevronUpIcon className="size-4" />
</SelectPrimitive.ScrollUpArrow>
);
}
function SelectScrollDownArrow({
className,
...props
}: React.ComponentProps<typeof SelectPrimitive.ScrollUpArrow>) {
return (
<SelectPrimitive.ScrollUpArrow
data-slot="select-scroll-down-arrow"
className={cn(
"bottom-0 z-[1] flex w-full cursor-default items-center justify-center py-2",
className
)}
{...props}
>
<ChevronDownIcon className="size-4" />
</SelectPrimitive.ScrollUpArrow>
);
}
function SelectSeparator({
className,
...props
}: Omit<
React.ComponentProps<typeof SelectPrimitive.Separator>,
"orientation"
>) {
return (
<SelectPrimitive.Separator
data-slot="select-separator"
className={cn("bg-border pointer-events-none -mx-1 my-1 h-px", className)}
{...props}
/>
);
}
export {
Select,
SelectTrigger,
SelectValue,
SelectBackdrop,
SelectPortal,
SelectItem,
SelectContent,
SelectGroup,
SelectGroupLabel,
SelectSeparator,
SelectScrollUpArrow,
SelectScrollDownArrow,
};
Update the import paths to match your project setup.
Usage
Import all parts and piece them together.
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
<Select>
<SelectTrigger>
<SelectValue placeholder="Theme" />
</SelectTrigger>
<SelectContent>
<SelectItem value="light">Light</SelectItem>
<SelectItem value="dark">Dark</SelectItem>
<SelectItem value="system">System</SelectItem>
</SelectContent>
</Select>
Examples
Groups
Select a job
Align Trigger
Theme