Displays a list of options for the user to pick from—triggered by a button.
1import {2 Select,3 SelectContent,4 SelectControl,Installation
pnpm dlx sprawlify@latest add selectnpx sprawlify@latest add selectyarn sprawlify@latest add selectbunx --bun sprawlify@latest add select
Install the following dependencies:
pnpm add @sprawlify/primitives @sprawlify/reactnpm install @sprawlify/primitives @sprawlify/reactyarn add @sprawlify/primitives @sprawlify/reactbun add @sprawlify/primitives @sprawlify/react
Add the following files to your project:
1"use client";23import * as React from "react";4import { cn } from "@/lib/utils";5import { sprawlify } from "@sprawlify/react";6import { Portal } from "@sprawlify/react/portal";7import { Select as SelectPrimitive } from "@sprawlify/react/select";8import { CheckIcon, ChevronsUpDownIcon } from "lucide-react";910const Select = SelectPrimitive.Root;1112const SelectControl = React.forwardRef<13 HTMLDivElement,14 React.ComponentProps<typeof SelectPrimitive.Control>15>(({ className, children, ...props }, ref) => (16 <SelectPrimitive.Control17 ref={ref}18 data-slot="select-control"19 className={cn("relative flex w-full items-center", className)}20 {...props}21 >22 {children}23 </SelectPrimitive.Control>24));25SelectControl.displayName = "SelectControl";2627const SelectTrigger = React.forwardRef<28 HTMLButtonElement,29 React.ComponentProps<typeof SelectPrimitive.Trigger>30>(({ className, children, ...props }, ref) => (31 <SelectPrimitive.Trigger32 ref={ref}33 data-slot="select-trigger"34 className={cn(35 "flex h-9 w-full items-center gap-2 rounded-md border border-input bg-input/30 py-2 pr-10 pl-3 text-sm shadow-xs transition-[border-color,box-shadow] duration-150 ease-in-out outline-none",36 "data-placeholder-shown:text-muted-foreground",37 "hover:border-ring/50",38 "focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/20",39 "data-disabled:cursor-not-allowed data-disabled:opacity-50",40 "data-invalid:border-destructive data-invalid:focus-visible:ring-destructive/20",41 className,42 )}43 {...props}44 >45 {children}46 </SelectPrimitive.Trigger>47));48SelectTrigger.displayName = "SelectTrigger";4950const SelectIndicatorGroup = React.forwardRef<51 HTMLDivElement,52 React.ComponentProps<typeof sprawlify.div>53>(({ className, children, ...props }, ref) => (54 <sprawlify.div55 ref={ref}56 data-slot="select-indicator-group"57 className={cn(58 "pointer-events-none absolute inset-y-0 right-0 flex items-center gap-1 px-2.5",59 className,60 )}61 {...props}62 >63 {children}64 </sprawlify.div>65));66SelectIndicatorGroup.displayName = "SelectIndicatorGroup";6768const SelectIndicator = React.forwardRef<69 HTMLDivElement,70 React.ComponentProps<typeof SelectPrimitive.Indicator>71>(({ className, children, ...props }, ref) => (72 <SelectPrimitive.Indicator73 ref={ref}74 data-slot="select-indicator"75 className={cn(76 "pointer-events-none absolute inset-y-0 right-0 flex items-center px-2.5 text-muted-foreground/60 [&_svg]:size-4",77 className,78 )}79 {...props}80 >81 {children ?? <ChevronsUpDownIcon />}82 </SelectPrimitive.Indicator>83));84SelectIndicator.displayName = "SelectIndicator";8586const SelectValue = React.forwardRef<87 HTMLSpanElement,88 React.ComponentProps<typeof SelectPrimitive.ValueText>89>(({ className, ...props }, ref) => (90 <SelectPrimitive.ValueText91 ref={ref}92 data-slot="select-value"93 className={cn("line-clamp-1 flex-1 text-left", className)}94 {...props}95 />96));97SelectValue.displayName = "SelectValue";9899const SelectPositioner = React.forwardRef<100 HTMLDivElement,101 React.ComponentProps<typeof SelectPrimitive.Positioner>102>(({ className, ...props }, ref) => (103 <SelectPrimitive.Positioner104 ref={ref}105 data-slot="select-positioner"106 className={cn("outline-none", className)}107 {...props}108 />109));110SelectPositioner.displayName = "SelectPositioner";111112const SelectContent = React.forwardRef<113 HTMLDivElement,114 React.ComponentProps<typeof SelectPrimitive.Content>115>(({ className, children, ...props }, ref) => (116 <Portal>117 <SelectPrimitive.Positioner data-slot="select-positioner" className="outline-none">118 <SelectPrimitive.Content119 ref={ref}120 data-slot="select-content"121 className={cn(122 "z-50 flex flex-col gap-0.5 rounded-lg border bg-popover p-1 text-popover-foreground shadow-lg outline-none",123 "min-w-(--reference-width)",124 "max-h-[min(var(--available-height,300px),300px)] overflow-y-auto",125 "origin-(--transform-origin)",126 "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-[98%]",127 "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-[98%]",128 className,129 )}130 {...props}131 >132 {children}133 </SelectPrimitive.Content>134 </SelectPrimitive.Positioner>135 </Portal>136));137SelectContent.displayName = "SelectContent";138139const SelectHiddenSelect = SelectPrimitive.HiddenSelect;140141const SelectItem = React.forwardRef<142 HTMLDivElement,143 React.ComponentProps<typeof SelectPrimitive.Item>144>(({ className, children, ...props }, ref) => (145 <SelectPrimitive.Item146 ref={ref}147 data-slot="select-item"148 className={cn(149 "relative flex w-full cursor-default items-center gap-2 rounded-md px-2 py-1.5 pr-8 text-sm outline-none select-none",150 "data-highlighted:bg-accent data-highlighted:text-accent-foreground",151 "data-[state=checked]:font-medium",152 "data-disabled:pointer-events-none data-disabled:opacity-50",153 className,154 )}155 {...props}156 >157 {children}158 </SelectPrimitive.Item>159));160SelectItem.displayName = "SelectItem";161162const SelectItemText = SelectPrimitive.ItemText;163164const SelectItemIndicator = React.forwardRef<165 HTMLDivElement,166 React.ComponentProps<typeof SelectPrimitive.ItemIndicator>167>(({ className, children, ...props }, ref) => (168 <SelectPrimitive.ItemIndicator169 ref={ref}170 data-slot="select-item-indicator"171 className={cn("absolute right-2 flex size-4 items-center justify-center", className)}172 {...props}173 >174 {children ?? <CheckIcon />}175 </SelectPrimitive.ItemIndicator>176));177SelectItemIndicator.displayName = "SelectItemIndicator";178179const SelectItemGroup = React.forwardRef<180 HTMLDivElement,181 React.ComponentProps<typeof SelectPrimitive.ItemGroup>182>(({ className, ...props }, ref) => (183 <SelectPrimitive.ItemGroup184 ref={ref}185 data-slot="select-item-group"186 className={cn("flex flex-col", className)}187 {...props}188 />189));190SelectItemGroup.displayName = "SelectItemGroup";191192const SelectItemGroupLabel = React.forwardRef<193 HTMLDivElement,194 React.ComponentProps<typeof SelectPrimitive.ItemGroupLabel>195>(({ className, ...props }, ref) => (196 <SelectPrimitive.ItemGroupLabel197 ref={ref}198 data-slot="select-item-group-label"199 className={cn(200 "px-2 py-1.5 text-xs font-semibold tracking-wide text-muted-foreground",201 className,202 )}203 {...props}204 />205));206SelectItemGroupLabel.displayName = "SelectItemGroupLabel";207208const SelectLabel = React.forwardRef<209 HTMLLabelElement,210 React.ComponentProps<typeof SelectPrimitive.Label>211>(({ className, ...props }, ref) => (212 <SelectPrimitive.Label213 ref={ref}214 data-slot="select-label"215 className={cn(216 "text-sm leading-none font-medium select-none data-disabled:opacity-50",217 className,218 )}219 {...props}220 />221));222SelectLabel.displayName = "SelectLabel";223224const SelectSeparator = React.forwardRef<225 HTMLDivElement,226 React.ComponentProps<typeof sprawlify.div>227>(({ className, ...props }, ref) => (228 <sprawlify.div229 ref={ref}230 data-slot="select-separator"231 className={cn("-mx-1 my-1 h-px bg-border", className)}232 {...props}233 />234));235SelectSeparator.displayName = "SelectSeparator";236237const SelectContext = SelectPrimitive.Context;238const SelectRootProvider = SelectPrimitive.RootProvider;239240export {241 Select,242 SelectControl,243 SelectTrigger,244 SelectIndicator,245 SelectValue,246 SelectPositioner,247 SelectContent,248 SelectHiddenSelect,249 SelectItem,250 SelectItemText,251 SelectItemIndicator,252 SelectItemGroup,253 SelectItemGroupLabel,254 SelectLabel,255 SelectSeparator,256 SelectIndicatorGroup,257 SelectContext,258 SelectRootProvider,259};260Update the import paths to match your project setup.
Usage
1import {
2 Select,
3 SelectClearTrigger,
4 SelectContent,
5 SelectControl,
6 SelectHiddenSelect,
7 SelectIndicator,
8 SelectIndicatorGroup,
9 SelectItem,
10 SelectItemGroup,
11 SelectItemGroupLabel,
12 SelectItemIndicator,
13 SelectItemText,
14 SelectTrigger,
15 SelectValue,
16} from "@/components/ui/select"1const collection = createListCollection({
2 items: [
3 { label: "Item 1", value: "item-1" },
4 { label: "Item 2", value: "item-2" },
5 { label: "Item 3", value: "item-3" },
6 { label: "Item 4", value: "item-4" },
7 { label: "Item 5", value: "item-5" },
8 ],
9})
10
11<Select collection={collection}>
12 <SelectHiddenSelect />
13 <SelectControl>
14 <SelectTrigger>
15 <SelectValue placeholder="Select an item" />
16 </SelectTrigger>
17 <SelectIndicatorGroup>
18 <SelectIndicator />
19 </SelectIndicatorGroup>
20 </SelectControl>
21 <SelectContent>
22 <SelectItemGroup>
23 <SelectItemGroupLabel>Fruits</SelectItemGroupLabel>
24 {collection.items.map((item) => (
25 <SelectItem key={item.value} item={item}>
26 <SelectItemText>{item.label}</SelectItemText>
27 <SelectItemIndicator />
28 </SelectItem>
29 ))}
30 </SelectItemGroup>
31 </SelectContent>
32</Select>Examples
Disabled
Add the disabled prop to the Select component to disable the select.
1import {2 Select,3 SelectContent,4 SelectControl,Groups
Use the groupBy option in createListCollection to organize items into groups.
1import {2 Select,3 SelectContent,4 SelectControl,Invalid
Use aria-invalid to show validation errors and the data-invalid attribute to the Field component for styling.
1import { Field, FieldError, FieldLabel } from "@/components/ui/field";2import {3 Select,4 SelectContent,Scrollable
1import {2 Select,3 SelectContent,4 SelectControl,Get PRO
Need premium blocks and templates? Upgrade to PRO and get access.