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/solidnpm install @sprawlify/primitives @sprawlify/solidyarn add @sprawlify/primitives @sprawlify/solidbun add @sprawlify/primitives @sprawlify/solid
Add the following files to your project:
1import { cn } from "@/lib/utils";2import { sprawlify } from "@sprawlify/solid";3import { Select as SelectPrimitive } from "@sprawlify/solid/select";4import { CheckIcon, ChevronsUpDownIcon } from "lucide-solid";5import { splitProps, type ComponentProps } from "solid-js";6import { Portal } from "solid-js/web";78function Select(props: ComponentProps<typeof SelectPrimitive.Root>) {9 return <SelectPrimitive.Root data-slot="select" {...props} />;10}1112function SelectControl(props: ComponentProps<typeof SelectPrimitive.Control>) {13 const [local, others] = splitProps(props, ["class", "children"]);1415 return (16 <SelectPrimitive.Control17 data-slot="select-control"18 class={cn("relative flex w-full items-center", local.class)}19 {...others}20 >21 {local.children}22 </SelectPrimitive.Control>23 );24}2526function SelectTrigger(props: ComponentProps<typeof SelectPrimitive.Trigger>) {27 const [local, others] = splitProps(props, ["class", "children"]);2829 return (30 <SelectPrimitive.Trigger31 data-slot="select-trigger"32 class={cn(33 "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",34 "data-placeholder-shown:text-muted-foreground",35 "hover:border-ring/50",36 "focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/20",37 "data-disabled:cursor-not-allowed data-disabled:opacity-50",38 "data-invalid:border-destructive data-invalid:focus-visible:ring-destructive/20",39 local.class,40 )}41 {...others}42 >43 <div class="flex gap-2">{local.children}</div>44 </SelectPrimitive.Trigger>45 );46}4748function SelectIndicatorGroup(props: ComponentProps<typeof sprawlify.div>) {49 const [local, others] = splitProps(props, ["class", "children"]);5051 return (52 <sprawlify.div53 data-slot="select-indicator-group"54 class={cn(55 "pointer-events-none absolute inset-y-0 right-0 flex items-center gap-1 px-2.5",56 local.class,57 )}58 {...others}59 >60 {local.children}61 </sprawlify.div>62 );63}6465function SelectIndicator(props: ComponentProps<typeof SelectPrimitive.Indicator>) {66 const [local, others] = splitProps(props, ["class", "children"]);6768 return (69 <SelectPrimitive.Indicator70 data-slot="select-indicator"71 class={cn(72 "pointer-events-none absolute inset-y-0 right-0 flex items-center px-2.5 text-muted-foreground/60 [&_svg]:size-4",73 local.class,74 )}75 {...others}76 >77 {local.children ?? <ChevronsUpDownIcon />}78 </SelectPrimitive.Indicator>79 );80}8182function SelectValue(props: ComponentProps<typeof SelectPrimitive.ValueText>) {83 const [local, others] = splitProps(props, ["class"]);8485 return (86 <SelectPrimitive.ValueText87 data-slot="select-value"88 class={cn("line-clamp-1 flex-1 text-left", local.class)}89 {...others}90 />91 );92}9394function SelectPositioner(props: ComponentProps<typeof SelectPrimitive.Positioner>) {95 const [local, others] = splitProps(props, ["class"]);9697 return (98 <SelectPrimitive.Positioner99 data-slot="select-positioner"100 class={cn("outline-none", local.class)}101 {...others}102 />103 );104}105106function SelectContent(props: ComponentProps<typeof SelectPrimitive.Content>) {107 const [local, others] = splitProps(props, ["class", "children"]);108109 return (110 <Portal>111 <SelectPrimitive.Positioner data-slot="select-positioner" class="outline-none">112 <SelectPrimitive.Content113 data-slot="select-content"114 class={cn(115 "z-50 flex flex-col gap-0.5 rounded-lg border bg-popover p-1 text-popover-foreground shadow-lg outline-none",116 "min-w-(--reference-width)",117 "max-h-[min(var(--available-height,300px),300px)] overflow-y-auto",118 "origin-(--transform-origin)",119 "data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-[98%]",120 "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-[98%]",121 local.class,122 )}123 {...others}124 >125 {local.children}126 </SelectPrimitive.Content>127 </SelectPrimitive.Positioner>128 </Portal>129 );130}131132const SelectHiddenSelect = SelectPrimitive.HiddenSelect;133134function SelectItem(props: ComponentProps<typeof SelectPrimitive.Item>) {135 const [local, others] = splitProps(props, ["class", "children"]);136137 return (138 <SelectPrimitive.Item139 data-slot="select-item"140 class={cn(141 "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",142 "data-highlighted:bg-accent data-highlighted:text-accent-foreground",143 "data-[state=checked]:font-medium",144 "data-disabled:pointer-events-none data-disabled:opacity-50",145 local.class,146 )}147 {...others}148 >149 {local.children}150 </SelectPrimitive.Item>151 );152}153154const SelectItemText = SelectPrimitive.ItemText;155156function SelectItemIndicator(props: ComponentProps<typeof SelectPrimitive.ItemIndicator>) {157 const [local, others] = splitProps(props, ["class", "children"]);158159 return (160 <SelectPrimitive.ItemIndicator161 data-slot="select-item-indicator"162 class={cn("absolute right-2 flex size-4 items-center justify-center", local.class)}163 {...others}164 >165 {local.children ?? <CheckIcon />}166 </SelectPrimitive.ItemIndicator>167 );168}169170function SelectItemGroup(props: ComponentProps<typeof SelectPrimitive.ItemGroup>) {171 const [local, others] = splitProps(props, ["class"]);172173 return (174 <SelectPrimitive.ItemGroup175 data-slot="select-item-group"176 class={cn("flex flex-col", local.class)}177 {...others}178 />179 );180}181182function SelectItemGroupLabel(props: ComponentProps<typeof SelectPrimitive.ItemGroupLabel>) {183 const [local, others] = splitProps(props, ["class"]);184185 return (186 <SelectPrimitive.ItemGroupLabel187 data-slot="select-item-group-label"188 class={cn(189 "px-2 py-1.5 text-xs font-semibold tracking-wide text-muted-foreground",190 local.class,191 )}192 {...others}193 />194 );195}196197function SelectLabel(props: ComponentProps<typeof SelectPrimitive.Label>) {198 const [local, others] = splitProps(props, ["class"]);199200 return (201 <SelectPrimitive.Label202 data-slot="select-label"203 class={cn(204 "text-sm leading-none font-medium select-none data-disabled:opacity-50",205 local.class,206 )}207 {...others}208 />209 );210}211212function SelectSeparator(props: ComponentProps<typeof sprawlify.div>) {213 const [local, others] = splitProps(props, ["class"]);214215 return (216 <sprawlify.div217 data-slot="select-separator"218 class={cn("-mx-1 my-1 h-px bg-border", local.class)}219 {...others}220 />221 );222}223224const SelectContext = SelectPrimitive.Context;225const SelectRootProvider = SelectPrimitive.RootProvider;226227export {228 Select,229 SelectControl,230 SelectTrigger,231 SelectIndicator,232 SelectValue,233 SelectPositioner,234 SelectContent,235 SelectHiddenSelect,236 SelectItem,237 SelectItemText,238 SelectItemIndicator,239 SelectItemGroup,240 SelectItemGroupLabel,241 SelectLabel,242 SelectSeparator,243 SelectIndicatorGroup,244 SelectContext,245 SelectRootProvider,246};247Update 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<CollectionItem>({
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.