Select
Displays a list of options for the user to pick from—triggered by a button.
The Select component wraps Kobalte's Select primitive. It is data-driven rather than compositional: pass an options array plus optionValue / optionTextValue accessors, and render each option through itemComponent.
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue,} from "~/components/ui/select";
const items = [ { label: "Apple", value: "apple" }, { label: "Banana", value: "banana" }, { label: "Blueberry", value: "blueberry" }, { label: "Grapes", value: "grapes" }, { label: "Pineapple", value: "pineapple" },];
export default function SelectDemo() { return ( <Select options={items} optionValue="value" optionTextValue="label" placeholder="Select a fruit" itemComponent={(props) => ( <SelectItem item={props.item}>{props.item.rawValue.label}</SelectItem> )} > <SelectTrigger aria-label="Fruit" class="w-full max-w-48"> <SelectValue<(typeof items)[number]>>{(state) => state.selectedOption().label}</SelectValue> </SelectTrigger> <SelectContent /> </Select> );}Installation
Usage
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue,} from "~/components/ui/select";
const items = [ { label: "Light", value: "light" }, { label: "Dark", value: "dark" }, { label: "System", value: "system" },];<Select options={items} optionValue="value" optionTextValue="label" placeholder="Theme" itemComponent={(props) => ( <SelectItem item={props.item}>{props.item.rawValue.label}</SelectItem> )}> <SelectTrigger aria-label="Theme" class="w-45"> <SelectValue<(typeof items)[number]>>{(state) => state.selectedOption().label}</SelectValue> </SelectTrigger> <SelectContent /></Select>See the Kobalte Select documentation for the full set of data-driven props (multiple, value / onChange, optionGroupChildren, etc.) supported by the root.
Composition
Select is data-driven: options are supplied once on the root, and SelectContent renders them internally through itemComponent. Use the following composition to build a Select:
Select (options, optionValue, optionTextValue, itemComponent, sectionComponent?)├── SelectTrigger│ └── SelectValue└── SelectContentitemComponent renders a SelectItem for each option. sectionComponent, used together with optionGroupChildren, renders a SelectGroup (with a SelectLabel and, optionally, a SelectSeparator) for each group of options.
Groups
Pass grouped data with optionGroupChildren and render a SelectGroup / SelectLabel per section from sectionComponent.
import { Show } from "solid-js";import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, SelectValue,} from "~/components/ui/select";
type FoodOption = { label: string; value: string;};
type Food = { label: string; options: FoodOption[];};
const foods: Food[] = [ { label: "Fruits", options: [ { label: "Apple", value: "apple" }, { label: "Banana", value: "banana" }, { label: "Blueberry", value: "blueberry" }, ], }, { label: "Vegetables", options: [ { label: "Carrot", value: "carrot" }, { label: "Broccoli", value: "broccoli" }, { label: "Spinach", value: "spinach" }, ], },];
export default function SelectGroups() { return ( <Select<FoodOption, Food> options={foods} optionValue="value" optionTextValue="label" optionGroupChildren="options" placeholder="Select a food" itemComponent={(props) => ( <SelectItem item={props.item}>{props.item.rawValue.label}</SelectItem> )} sectionComponent={(props) => ( <> <Show when={props.section.index !== 0}> <SelectSeparator /> </Show> <SelectGroup> <SelectLabel>{props.section.rawValue.label}</SelectLabel> </SelectGroup> </> )} > <SelectTrigger aria-label="Food" class="w-full max-w-48"> <SelectValue<FoodOption>>{(state) => state.selectedOption().label}</SelectValue> </SelectTrigger> <SelectContent /> </Select> );}Scrollable
A select with many items, grouped by region, that scrolls.
import { Show } from "solid-js";import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, SelectValue,} from "~/components/ui/select";
type TimezoneOption = { label: string; value: string;};
type Region = { label: string; options: TimezoneOption[];};
const regions: Region[] = [ { label: "North America", options: [ { 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" }, ], }, { label: "Europe & Africa", options: [ { 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" }, ], }, { label: "Asia", options: [ { 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" }, ], }, { label: "Australia & Pacific", options: [ { 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" }, ], }, { label: "South America", options: [ { label: "Argentina Time", value: "art" }, { label: "Bolivia Time", value: "bot" }, { label: "Brasilia Time", value: "brt" }, { label: "Chile Standard Time", value: "clt" }, ], },];
export default function SelectScrollable() { return ( <Select<TimezoneOption, Region> options={regions} optionValue="value" optionTextValue="label" optionGroupChildren="options" placeholder="Select a timezone" itemComponent={(props) => ( <SelectItem item={props.item}>{props.item.rawValue.label}</SelectItem> )} sectionComponent={(props) => ( <> <Show when={props.section.index !== 0}> <SelectSeparator /> </Show> <SelectGroup> <SelectLabel>{props.section.rawValue.label}</SelectLabel> </SelectGroup> </> )} > <SelectTrigger aria-label="Time zone" class="w-full max-w-64"> <SelectValue<TimezoneOption>>{(state) => state.selectedOption().label}</SelectValue> </SelectTrigger> <SelectContent /> </Select> );}Disabled
Pass disabled on Select to disable the whole control, or optionDisabled to disable individual options.
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue,} from "~/components/ui/select";
const items = [ { label: "Apple", value: "apple", disabled: false }, { label: "Banana", value: "banana", disabled: false }, { label: "Blueberry", value: "blueberry", disabled: false }, { label: "Grapes", value: "grapes", disabled: true }, { label: "Pineapple", value: "pineapple", disabled: false },];
export default function SelectDisabled() { return ( <Select options={items} optionValue="value" optionTextValue="label" optionDisabled="disabled" placeholder="Select a fruit" disabled itemComponent={(props) => ( <SelectItem item={props.item}>{props.item.rawValue.label}</SelectItem> )} > <SelectTrigger aria-label="Fruit" class="w-full max-w-48"> <SelectValue<(typeof items)[number]>>{(state) => state.selectedOption().label}</SelectValue> </SelectTrigger> <SelectContent /> </Select> );}Invalid
Add the data-invalid attribute to the Field component, set validationState="invalid" on Select, and add the aria-invalid attribute to the SelectTrigger component to show an error state.
<Field data-invalid> <FieldLabel for="fruit">Fruit</FieldLabel> <Select validationState="invalid" /* options, itemComponent, ... */> <SelectTrigger id="fruit" aria-invalid> <SelectValue /> </SelectTrigger> <SelectContent /> </Select></Field>import { Field, FieldError, FieldLabel } from "~/components/ui/field";import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue,} from "~/components/ui/select";
const items = [ { label: "Apple", value: "apple" }, { label: "Banana", value: "banana" }, { label: "Blueberry", value: "blueberry" },];
export default function SelectInvalid() { return ( <Field data-invalid class="w-full max-w-48"> <FieldLabel for="invalid-fruit">Fruit</FieldLabel> <Select options={items} optionValue="value" optionTextValue="label" placeholder="Select a fruit" validationState="invalid" itemComponent={(props) => ( <SelectItem item={props.item}>{props.item.rawValue.label}</SelectItem> )} > <SelectTrigger id="invalid-fruit" aria-invalid> <SelectValue<(typeof items)[number]>> {(state) => state.selectedOption().label} </SelectValue> </SelectTrigger> <SelectContent /> </Select> <FieldError>Please select a fruit.</FieldError> </Field> );}API Reference
The Select component uses Kobalte's Select primitive under the hood. Here are the main props:
SelectTrigger
SelectContent
Renders the dropdown portal and listbox. It takes no children—options are rendered internally from the root's options and itemComponent.
SelectItem
SelectGroup / SelectLabel / SelectSeparator
Used inside sectionComponent to render a labeled group of options, optionally separated from the previous group by a SelectSeparator.
See the Kobalte Select API reference for the complete prop list.