Select
HeroUIA button that chooses one or many options from a list, HeroUI's on Kobalte's.
Solidtype_heroui.Select is Kobalte’s Select, with the classes HeroUI’s
own selectVariants gives. Its list is a List_box inside its popover, as
in HeroUI; Label, Description and Field_error inside it name, describe
and qualify it.
module Label = Solidtype_heroui.Labelmodule List_box = Solidtype_heroui.List_boxmodule Select = Solidtype_heroui.Select
let make () = <Select class_="w-[256px]" placeholder="Select one"> <Label>"State"</Label> <Select.Trigger><Select.Value /> <Select.Indicator /></Select.Trigger> <Select.Popover> <List_box> <List_box.Item id="florida" text_value="Florida"> "Florida" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="delaware" text_value="Delaware"> "Delaware" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="california" text_value="California"> "California" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="texas" text_value="Texas"> "Texas" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="new-york" text_value="New York"> "New York" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="washington" text_value="Washington"> "Washington" <List_box.Item_indicator /> </List_box.Item> </List_box> </Select.Popover> </Select>Anatomy
Section titled “Anatomy”<Select> <Label>...</Label> <Select.Trigger> <Select.Value /> <Select.Clear_button /> <Select.Indicator /> </Select.Trigger> <Description>...</Description> <Select.Popover> <List_box> <List_box.Item id="...">...</List_box.Item> </List_box> </Select.Popover></Select>Examples
Section titled “Examples”Variants
Section titled “Variants”module Label = Solidtype_heroui.Labelmodule List_box = Solidtype_heroui.List_boxmodule Select = Solidtype_heroui.Select
let make () = <div class_="flex flex-col gap-4"> <Select class_="w-[256px]" placeholder="Select one" variant=`primary> <Label>"Primary variant"</Label> <Select.Trigger><Select.Value /> <Select.Indicator /></Select.Trigger> <Select.Popover> <List_box> <List_box.Item id="option1" text_value="Option 1"> "Option 1" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="option2" text_value="Option 2"> "Option 2" <List_box.Item_indicator /> </List_box.Item> </List_box> </Select.Popover> </Select> <Select class_="w-[256px]" placeholder="Select one" variant=`secondary> <Label>"Secondary variant"</Label> <Select.Trigger><Select.Value /> <Select.Indicator /></Select.Trigger> <Select.Popover> <List_box> <List_box.Item id="option1" text_value="Option 1"> "Option 1" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="option2" text_value="Option 2"> "Option 2" <List_box.Item_indicator /> </List_box.Item> </List_box> </Select.Popover> </Select> </div>Full Width
Section titled “Full Width”module Label = Solidtype_heroui.Labelmodule List_box = Solidtype_heroui.List_boxmodule Select = Solidtype_heroui.Select
let make () = <div class_="w-[400px] space-y-4"> <Select full_width=true placeholder="Select one"> <Label>"Favorite Animal"</Label> <Select.Trigger><Select.Value /> <Select.Indicator /></Select.Trigger> <Select.Popover> <List_box> <List_box.Item id="cat" text_value="Cat"> "Cat" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="dog" text_value="Dog"> "Dog" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="bird" text_value="Bird"> "Bird" <List_box.Item_indicator /> </List_box.Item> </List_box> </Select.Popover> </Select> </div>With Description
Section titled “With Description”module Description = Solidtype_heroui.Descriptionmodule Label = Solidtype_heroui.Labelmodule List_box = Solidtype_heroui.List_boxmodule Select = Solidtype_heroui.Select
let make () = <Select class_="w-[256px]" placeholder="Select one"> <Label>"State"</Label> <Select.Trigger><Select.Value /> <Select.Indicator /></Select.Trigger> <Select.Popover> <List_box> <List_box.Item id="florida" text_value="Florida"> "Florida" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="delaware" text_value="Delaware"> "Delaware" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="california" text_value="California"> "California" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="texas" text_value="Texas"> "Texas" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="new-york" text_value="New York"> "New York" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="washington" text_value="Washington"> "Washington" <List_box.Item_indicator /> </List_box.Item> </List_box> </Select.Popover> <Description>"Select your state of residence"</Description> </Select>Required
Section titled “Required”HeroUI’s required select is checked by the browser as its form is
submitted. A Form here checks nothing itself, as with a text field: the
example says the select is invalid once a submit finds it empty.
module S = Solidtype.Solidmodule Button = Solidtype_heroui.Buttonmodule Field_error = Solidtype_heroui.Field_errormodule Form = Solidtype_heroui.Formmodule Label = Solidtype_heroui.Labelmodule List_box = Solidtype_heroui.List_boxmodule Select = Solidtype_heroui.Select
external prevent_default : Dom.event -> unit = "preventDefault" [@@mel.send]
let make () = let state, set_state = S.create_signal [||] in let country, set_country = S.create_signal [||] in (* A required select shows its error once a submit has been tried, as the browser's validation React Aria reads does. *) let tried, set_tried = S.create_signal false in let missing chosen = S.get tried && Array.length (S.get chosen) = 0 in <Form class_="flex w-[256px] flex-col gap-4" on_submit=(fun e -> prevent_default e; S.set set_tried true)> <Select is_required=true is_invalid=(fun () -> missing state) class_="w-full" name="state" placeholder="Select one" on_change=(S.set set_state)> <Label>"State"</Label> <Select.Trigger><Select.Value /> <Select.Indicator /></Select.Trigger> <Select.Popover> <List_box> <List_box.Item id="florida" text_value="Florida"> "Florida" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="delaware" text_value="Delaware"> "Delaware" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="california" text_value="California"> "California" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="texas" text_value="Texas"> "Texas" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="new-york" text_value="New York"> "New York" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="washington" text_value="Washington"> "Washington" <List_box.Item_indicator /> </List_box.Item> </List_box> </Select.Popover> <Field_error>"Please select an item in the list."</Field_error> </Select> <Select is_required=true is_invalid=(fun () -> missing country) class_="w-full" name="country" placeholder="Select a country" on_change=(S.set set_country)> <Label>"Country"</Label> <Select.Trigger><Select.Value /> <Select.Indicator /></Select.Trigger> <Select.Popover> <List_box> <List_box.Item id="usa" text_value="United States"> "United States" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="canada" text_value="Canada"> "Canada" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="mexico" text_value="Mexico"> "Mexico" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="uk" text_value="United Kingdom"> "United Kingdom" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="france" text_value="France"> "France" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="germany" text_value="Germany"> "Germany" <List_box.Item_indicator /> </List_box.Item> </List_box> </Select.Popover> <Field_error>"Please select an item in the list."</Field_error> </Select> <Button type_=`submit>"Submit"</Button> </Form>Disabled
Section titled “Disabled”module Label = Solidtype_heroui.Labelmodule List_box = Solidtype_heroui.List_boxmodule Select = Solidtype_heroui.Select
let make () = <div class_="flex flex-col gap-4"> <Select is_disabled=true class_="w-[256px]" default_value=(fun () -> [| "california" |]) placeholder="Select one"> <Label>"State"</Label> <Select.Trigger><Select.Value /> <Select.Indicator /></Select.Trigger> <Select.Popover> <List_box> <List_box.Item id="florida" text_value="Florida"> "Florida" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="delaware" text_value="Delaware"> "Delaware" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="california" text_value="California"> "California" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="texas" text_value="Texas"> "Texas" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="new-york" text_value="New York"> "New York" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="washington" text_value="Washington"> "Washington" <List_box.Item_indicator /> </List_box.Item> </List_box> </Select.Popover> </Select> <Select is_disabled=true class_="w-[256px]" default_value=(fun () -> [| "argentina"; "japan"; "france" |]) placeholder="Select countries" selection_mode=`multiple> <Label>"Countries to Visit"</Label> <Select.Trigger><Select.Value /> <Select.Indicator /></Select.Trigger> <Select.Popover> <List_box> <List_box.Item id="argentina" text_value="Argentina"> "Argentina" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="venezuela" text_value="Venezuela"> "Venezuela" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="japan" text_value="Japan"> "Japan" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="france" text_value="France"> "France" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="italy" text_value="Italy"> "Italy" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="spain" text_value="Spain"> "Spain" <List_box.Item_indicator /> </List_box.Item> </List_box> </Select.Popover> </Select> </div>With Disabled Options
Section titled “With Disabled Options”module Label = Solidtype_heroui.Labelmodule List_box = Solidtype_heroui.List_boxmodule Select = Solidtype_heroui.Select
let make () = <Select class_="w-[256px]" disabled_keys=(fun () -> [| "cat"; "kangaroo" |]) placeholder="Select an animal"> <Label>"Animal"</Label> <Select.Trigger><Select.Value /> <Select.Indicator /></Select.Trigger> <Select.Popover> <List_box> <List_box.Item id="dog" text_value="Dog"> "Dog" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="cat" text_value="Cat"> "Cat" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="bird" text_value="Bird"> "Bird" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="kangaroo" text_value="Kangaroo"> "Kangaroo" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="elephant" text_value="Elephant"> "Elephant" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="tiger" text_value="Tiger"> "Tiger" <List_box.Item_indicator /> </List_box.Item> </List_box> </Select.Popover> </Select>Multiple Select
Section titled “Multiple Select”module Label = Solidtype_heroui.Labelmodule List_box = Solidtype_heroui.List_boxmodule Select = Solidtype_heroui.Select
let make () = <Select class_="w-[256px]" placeholder="Select countries" selection_mode=`multiple> <Label>"Countries to Visit"</Label> <Select.Trigger><Select.Value /> <Select.Indicator /></Select.Trigger> <Select.Popover> <List_box selection_mode=`multiple> <List_box.Item id="argentina" text_value="Argentina"> "Argentina" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="venezuela" text_value="Venezuela"> "Venezuela" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="japan" text_value="Japan"> "Japan" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="france" text_value="France"> "France" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="italy" text_value="Italy"> "Italy" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="spain" text_value="Spain"> "Spain" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="thailand" text_value="Thailand"> "Thailand" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="new-zealand" text_value="New Zealand"> "New Zealand" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="iceland" text_value="Iceland"> "Iceland" <List_box.Item_indicator /> </List_box.Item> </List_box> </Select.Popover> </Select>With Sections
Section titled “With Sections”module Header = Solidtype_heroui.Headermodule Label = Solidtype_heroui.Labelmodule List_box = Solidtype_heroui.List_boxmodule Select = Solidtype_heroui.Selectmodule Separator = Solidtype_heroui.Separator
let make () = <Select class_="w-[256px]" placeholder="Select a country"> <Label>"Country"</Label> <Select.Trigger><Select.Value /> <Select.Indicator /></Select.Trigger> <Select.Popover> <List_box> <List_box.Section> <Header>"North America"</Header> <List_box.Item id="usa" text_value="United States"> "United States" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="canada" text_value="Canada"> "Canada" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="mexico" text_value="Mexico"> "Mexico" <List_box.Item_indicator /> </List_box.Item> </List_box.Section> <Separator /> <List_box.Section> <Header>"Europe"</Header> <List_box.Item id="uk" text_value="United Kingdom"> "United Kingdom" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="france" text_value="France"> "France" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="germany" text_value="Germany"> "Germany" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="spain" text_value="Spain"> "Spain" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="italy" text_value="Italy"> "Italy" <List_box.Item_indicator /> </List_box.Item> </List_box.Section> <Separator /> <List_box.Section> <Header>"Asia"</Header> <List_box.Item id="japan" text_value="Japan"> "Japan" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="china" text_value="China"> "China" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="india" text_value="India"> "India" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="south-korea" text_value="South Korea"> "South Korea" <List_box.Item_indicator /> </List_box.Item> </List_box.Section> </List_box> </Select.Popover> </Select>Controlled
Section titled “Controlled”Selected: California
module S = Solidtype.Solidmodule Jsx = Solidtype.Jsxmodule Label = Solidtype_heroui.Labelmodule List_box = Solidtype_heroui.List_boxmodule Select = Solidtype_heroui.Select
type state = { id : string; name : string }
let states = [| { id = "california"; name = "California" }; { id = "texas"; name = "Texas" }; { id = "florida"; name = "Florida" }; { id = "new-york"; name = "New York" }; { id = "illinois"; name = "Illinois" }; { id = "pennsylvania"; name = "Pennsylvania" }; |]
let make () = let state, set_state = S.create_signal [| "california" |] in let selected_state () = Array.find_opt (fun s -> Array.exists (String.equal s.id) (S.get state)) states in <div class_="space-y-2"> <Select class_="w-[256px]" placeholder="Select a state" value=(fun () -> S.get state) on_change=(fun value -> S.set set_state value)> <Label>"State (controlled)"</Label> <Select.Trigger><Select.Value /> <Select.Indicator /></Select.Trigger> <Select.Popover> <List_box> <Solidtype.For each=(fun () -> states)> (fun (state : state) _ -> <List_box.Item id=(fun () -> state.id) text_value=(fun () -> state.name)> (fun () -> Jsx.string state.name) <List_box.Item_indicator /> </List_box.Item>) </Solidtype.For> </List_box> </Select.Popover> </Select> <p class_="text-sm text-muted"> "Selected: " (fun () -> Jsx.string (match selected_state () with Some s -> s.name | None -> "None")) </p> </div>Controlled Multiple
Section titled “Controlled Multiple”Selected: california, texas
module S = Solidtype.Solidmodule Jsx = Solidtype.Jsxmodule Label = Solidtype_heroui.Labelmodule List_box = Solidtype_heroui.List_boxmodule Select = Solidtype_heroui.Select
let make () = let selected, set_selected = S.create_signal [| "california"; "texas" |] in <div class_="space-y-4"> <Select class_="w-[256px]" placeholder="Select states" selection_mode=`multiple value=(fun () -> S.get selected) on_change=(fun keys -> S.set set_selected keys)> <Label>"States (controlled multiple)"</Label> <Select.Trigger><Select.Value /> <Select.Indicator /></Select.Trigger> <Select.Popover> <List_box selection_mode=`multiple> <List_box.Item id="california" text_value="California"> "California" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="texas" text_value="Texas"> "Texas" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="florida" text_value="Florida"> "Florida" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="new-york" text_value="New York"> "New York" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="illinois" text_value="Illinois"> "Illinois" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="pennsylvania" text_value="Pennsylvania"> "Pennsylvania" <List_box.Item_indicator /> </List_box.Item> </List_box> </Select.Popover> </Select> <p class_="text-sm text-muted"> "Selected: " (fun () -> Jsx.string (match S.get selected with | [||] -> "None" | keys -> String.concat ", " (Array.to_list keys))) </p> </div>Controlled Open State
Section titled “Controlled Open State”Select is closed
module S = Solidtype.Solidmodule Jsx = Solidtype.Jsxmodule Button = Solidtype_heroui.Buttonmodule Label = Solidtype_heroui.Labelmodule List_box = Solidtype_heroui.List_boxmodule Select = Solidtype_heroui.Select
let make () = let is_open, set_is_open = S.create_signal false in <div class_="space-y-4"> <Select class_="w-[256px]" is_open=(fun () -> S.get is_open) placeholder="Select one" on_open_change=(S.set set_is_open)> <Label>"State"</Label> <Select.Trigger><Select.Value /> <Select.Indicator /></Select.Trigger> <Select.Popover> <List_box> <List_box.Item id="florida" text_value="Florida"> "Florida" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="delaware" text_value="Delaware"> "Delaware" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="california" text_value="California"> "California" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="texas" text_value="Texas"> "Texas" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="new-york" text_value="New York"> "New York" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="washington" text_value="Washington"> "Washington" <List_box.Item_indicator /> </List_box.Item> </List_box> </Select.Popover> </Select> <Button on_click=(fun _ -> S.set set_is_open (not (S.get is_open)))> (fun () -> Jsx.string (if S.get is_open then "Close" else "Open")) " Select" </Button> <p class_="text-sm text-muted"> "Select is " (fun () -> Jsx.string (if S.get is_open then "open" else "closed")) </p> </div>Asynchronous Loading
Section titled “Asynchronous Loading”HeroUI’s example fetches its list from a server; here the same names are
loaded a part at a time. The list’s List_box.Load_more_item is React
Aria’s ListBoxLoadMoreItem: it asks for more as the list scrolls to its
end, and shows its children while more load.
module S = Solidtype.Solidmodule Jsx = Solidtype.Jsxmodule Label = Solidtype_heroui.Labelmodule List_box = Solidtype_heroui.List_boxmodule Select = Solidtype_heroui.Selectmodule Spinner = Solidtype_heroui.Spinner
(* The first page of https://pokeapi.co/api/v2/pokemon, which HeroUI's example fetches, here loaded a part at a time. *)let pokemon = [| "bulbasaur"; "ivysaur"; "venusaur"; "charmander"; "charmeleon"; "charizard"; "squirtle"; "wartortle"; "blastoise"; "caterpie"; "metapod"; "butterfree"; "weedle"; "kakuna"; "beedrill"; "pidgey"; "pidgeotto"; "pidgeot"; "rattata"; "raticate"; |]
(* How long the fetch it stands in for takes, and how many each brings. *)let load_ms = 800let page = 10
let make () = let loaded, set_loaded = S.create_signal 0 in let loading, set_loading = S.create_signal false in let load_more () = let now = S.get loaded in if (not (S.get loading)) && now < Array.length pokemon then ( S.set set_loading true; let timer = Js.Global.setTimeout ~f:(fun () -> S.set set_loaded (min (Array.length pokemon) (now + page)); S.set set_loading false) load_ms in S.on_cleanup (fun () -> Js.Global.clearTimeout timer)) in S.on_mount load_more; <Select class_="w-[256px]" placeholder="Select a Pokemon"> <Label>"Pick a Pokemon"</Label> <Select.Trigger><Select.Value /> <Select.Indicator /></Select.Trigger> <Select.Popover> <List_box> <Solidtype.For each=(fun () -> Array.sub pokemon 0 (S.get loaded))> (fun name _ -> <List_box.Item id=(fun () -> name) text_value=(fun () -> name)> (fun () -> Jsx.string name) <List_box.Item_indicator /> </List_box.Item>) </Solidtype.For> <List_box.Load_more_item is_loading=(fun () -> S.get loading) on_load_more=load_more> <div class_="flex items-center justify-center gap-2 py-2"> <Spinner size=`sm /> <span class_="text-sm text-muted">"Loading more..."</span> </div> </List_box.Load_more_item> </List_box> </Select.Popover> </Select>Custom Indicator
Section titled “Custom Indicator”module Label = Solidtype_heroui.Labelmodule List_box = Solidtype_heroui.List_boxmodule Select = Solidtype_heroui.Select
let make () = <Select class_="w-[256px]" placeholder="Select one"> <Label>"State"</Label> <Select.Trigger> <Select.Value /> <Select.Indicator class_="size-3"> <Gravity.Chevrons_expand_vertical /> </Select.Indicator> </Select.Trigger> <Select.Popover> <List_box> <List_box.Item id="florida" text_value="Florida"> "Florida" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="delaware" text_value="Delaware"> "Delaware" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="california" text_value="California"> "California" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="texas" text_value="Texas"> "Texas" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="new-york" text_value="New York"> "New York" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="washington" text_value="Washington"> "Washington" <List_box.Item_indicator /> </List_box.Item> </List_box> </Select.Popover> </Select>With Clear Button
Section titled “With Clear Button”module Label = Solidtype_heroui.Labelmodule List_box = Solidtype_heroui.List_boxmodule Select = Solidtype_heroui.Select
let make () = <Select class_="w-[256px]" default_value=(fun () -> [| "california" |]) placeholder="Select one"> <Label>"State"</Label> <Select.Trigger> <Select.Value /> <Select.Clear_button /> <Select.Indicator /> </Select.Trigger> <Select.Popover> <List_box> <List_box.Item id="florida" text_value="Florida"> "Florida" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="delaware" text_value="Delaware"> "Delaware" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="california" text_value="California"> "California" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="texas" text_value="Texas"> "Texas" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="new-york" text_value="New York"> "New York" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="washington" text_value="Washington"> "Washington" <List_box.Item_indicator /> </List_box.Item> </List_box> </Select.Popover> </Select>Custom Value
Section titled “Custom Value”Select.Value’s children are a function of the ids chosen, drawn while
one is; the select draws its placeholder while none is.
module S = Solidtype.Solidmodule Jsx = Solidtype.Jsxmodule Avatar = Solidtype_heroui.Avatarmodule Description = Solidtype_heroui.Descriptionmodule Label = Solidtype_heroui.Labelmodule List_box = Solidtype_heroui.List_boxmodule Select = Solidtype_heroui.Select
type user = { avatar_url : string; email : string; fallback : string; id : string; name : string;}
let users = [| { avatar_url = "https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/blue.jpg"; email = "bob@heroui.com"; fallback = "B"; id = "1"; name = "Bob"; }; { avatar_url = "https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/green.jpg"; email = "fred@heroui.com"; fallback = "F"; id = "2"; name = "Fred"; }; { avatar_url = "https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/purple.jpg"; email = "martha@heroui.com"; fallback = "M"; id = "3"; name = "Martha"; }; { avatar_url = "https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/red.jpg"; email = "john@heroui.com"; fallback = "J"; id = "4"; name = "John"; }; { avatar_url = "https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/orange.jpg"; email = "jane@heroui.com"; fallback = "J"; id = "5"; name = "Jane"; }; |]
let make () = <Select class_="w-[256px]" placeholder="Select a user"> <Label>"User"</Label> <Select.Trigger> <Select.Value> (fun keys -> <span class_="contents"> (fun () -> match S.get keys with | [| key |] -> ( match Array.find_opt (fun (user : user) -> String.equal user.id key) users with | Some user -> Jsx.element <div class_="flex items-center gap-2"> <Avatar class_="size-4" size=`sm> <Avatar.Image src=(fun () -> user.avatar_url) /> <Avatar.Fallback> (fun () -> Jsx.string user.fallback) </Avatar.Fallback> </Avatar> <span>(fun () -> Jsx.string user.name)</span> </div> | None -> Jsx.element Jsx.nothing) | keys -> Jsx.string (string_of_int (Array.length keys) ^ " users selected")) </span>) </Select.Value> <Select.Indicator /> </Select.Trigger> <Select.Popover> <List_box> <Solidtype.For each=(fun () -> users)> (fun (user : user) _ -> <List_box.Item id=(fun () -> user.id) text_value=(fun () -> user.name)> <Avatar size=`sm> <Avatar.Image src=(fun () -> user.avatar_url) /> <Avatar.Fallback> (fun () -> Jsx.string user.fallback) </Avatar.Fallback> </Avatar> <div class_="flex flex-col"> <Label>(fun () -> Jsx.string user.name)</Label> <Description>(fun () -> Jsx.string user.email)</Description> </div> <List_box.Item_indicator /> </List_box.Item>) </Solidtype.For> </List_box> </Select.Popover> </Select>In Surface
Section titled “In Surface”module S = Solidtype.Solidmodule Button = Solidtype_heroui.Buttonmodule Field_error = Solidtype_heroui.Field_errormodule Form = Solidtype_heroui.Formmodule Label = Solidtype_heroui.Labelmodule List_box = Solidtype_heroui.List_boxmodule Select = Solidtype_heroui.Selectmodule Surface = Solidtype_heroui.Surface
external prevent_default : Dom.event -> unit = "preventDefault" [@@mel.send]
let make () = let state, set_state = S.create_signal [||] in let country, set_country = S.create_signal [||] in (* A required select shows its error once a submit has been tried, as the browser's validation React Aria reads does. *) let tried, set_tried = S.create_signal false in let missing chosen = S.get tried && Array.length (S.get chosen) = 0 in <Surface class_="w-[320px] rounded-3xl p-6"> <Form class_="flex w-full flex-col gap-4" on_submit=(fun e -> prevent_default e; S.set set_tried true)> <Select is_required=true is_invalid=(fun () -> missing state) class_="w-full" name="state" placeholder="Select one" variant=`secondary on_change=(S.set set_state)> <Label>"State"</Label> <Select.Trigger><Select.Value /> <Select.Indicator /></Select.Trigger> <Select.Popover> <List_box> <List_box.Item id="florida" text_value="Florida"> "Florida" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="delaware" text_value="Delaware"> "Delaware" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="california" text_value="California"> "California" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="texas" text_value="Texas"> "Texas" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="new-york" text_value="New York"> "New York" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="washington" text_value="Washington"> "Washington" <List_box.Item_indicator /> </List_box.Item> </List_box> </Select.Popover> <Field_error>"Please select an item in the list."</Field_error> </Select> <Select is_required=true is_invalid=(fun () -> missing country) class_="w-full" name="country" placeholder="Select a country" variant=`secondary on_change=(S.set set_country)> <Label>"Country"</Label> <Select.Trigger><Select.Value /> <Select.Indicator /></Select.Trigger> <Select.Popover> <List_box> <List_box.Item id="usa" text_value="United States"> "United States" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="canada" text_value="Canada"> "Canada" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="mexico" text_value="Mexico"> "Mexico" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="uk" text_value="United Kingdom"> "United Kingdom" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="france" text_value="France"> "France" <List_box.Item_indicator /> </List_box.Item> <List_box.Item id="germany" text_value="Germany"> "Germany" <List_box.Item_indicator /> </List_box.Item> </List_box> </Select.Popover> <Field_error>"Please select an item in the list."</Field_error> </Select> <Button type_=`submit>"Submit"</Button> </Form> </Surface>Render Function
Section titled “Render Function”HeroUI’s Render Function example gives the select render, React’s way to
swap the element it renders, which a Solid component has no need of.
Customization
Section titled “Customization”Tailwind CSS
Section titled “Tailwind CSS”class_ is added after HeroUI’s classes.
module Label = Solidtype_heroui.Labelmodule List_box = Solidtype_heroui.List_boxmodule Select = Solidtype_heroui.Select
let item_class = "rounded-lg data-[focused=true]:bg-accent/10 \ data-[selected=true]:text-foreground"
let make () = <Select class_="w-56" placeholder="Pick a plan" variant=`secondary> <Label class_="font-medium text-foreground">"Plan"</Label> <Select.Trigger class_="rounded-xl bg-default"> <Select.Value /> <Select.Indicator /> </Select.Trigger> <Select.Popover class_="rounded-xl border border-border bg-surface p-1 shadow-lg"> <List_box> <List_box.Item class_=(fun () -> item_class) id="free" text_value="Free"> "Free" <List_box.Item_indicator /> </List_box.Item> <List_box.Item class_=(fun () -> item_class) id="pro" text_value="Pro"> "Pro" <List_box.Item_indicator /> </List_box.Item> </List_box> </Select.Popover> </Select>Global CSS
Section titled “Global CSS”HeroUI’s classes are global, so a stylesheet restyles every one, as with HeroUI in React:
@layer components { .select__trigger { @apply rounded-lg border border-border bg-surface; }
.select__popover { @apply rounded-xl; }}Styling Reference
Section titled “Styling Reference”CSS Classes
Section titled “CSS Classes”.select,.select--primary,.select--secondary,.select--full-width.select__trigger,.select__value,.select__indicator,.select__clear-button,.select__popover
Interactive States
Section titled “Interactive States”- Open:
[data-open="true"]on the select and its indicator - Focus:
[data-focused="true"]and[data-focus-visible="true"]on the select and its trigger - Hover and Pressed:
[data-hovered="true"],[data-pressed="true"]on the trigger - Placeholder:
[data-placeholder="true"]on the value - Empty:
[data-empty="true"]on the clear button - Invalid, Disabled, Required:
[data-invalid="true"],[data-disabled="true"],[data-required="true"]on the select - Entering and Exiting:
[data-entering="true"],[data-exiting="true"]on the popover
How it is made
Section titled “How it is made”Kobalte’s select opens its list from its trigger, moves the focus through it
by the arrows and by what is typed, chooses one option or many, and closes
on Escape or a press outside, giving the focus back to its trigger, as React
Aria’s does. Its list is the List_box inside its popover, which a select
takes as its own: the list’s options join the select while it is closed
too, so its value can draw the option chosen as the list draws it, and are
Kobalte’s select’s options. While it is open the page outside is hidden from
a reader, as React Aria’s modal popover hides it.
A clear button is a <span> inside the trigger, since a button in a button
is not HTML, so Backspace or Delete on the trigger clears too, as HeroUI’s
does.
API Reference
Section titled “API Reference”Each prop beside the name HeroUI’s React component gives it.
Select
Section titled “Select”| React | solidtype | Type | Default | Description |
|---|---|---|---|---|
placeholder |
placeholder |
string |
"Select an item" |
Shown while nothing is chosen |
selectionMode |
selection_mode |
`single | `multiple |
`single |
One or many, read as it is made |
value |
value |
string array |
The ids chosen, controlled | |
defaultValue |
default_value |
string array |
The ids chosen at first | |
onChange |
on_change |
string array -> unit |
Told the ids chosen as they change | |
onClear |
on_clear |
unit -> unit |
Told as it is cleared | |
disabledKeys |
disabled_keys |
string array |
The disabled options’ ids | |
isOpen |
is_open |
bool |
Whether its list is open, controlled | |
defaultOpen |
default_open |
bool |
false |
Whether it starts open |
onOpenChange |
on_open_change |
bool -> unit |
Told as it opens or closes | |
isDisabled |
is_disabled |
bool |
false |
Whether it is disabled |
isRequired |
is_required |
bool |
false |
Whether a choice is required |
isInvalid |
is_invalid |
bool |
false |
Whether it is invalid |
name |
name |
string |
Its name in a form | |
fullWidth |
full_width |
bool |
false |
Whether it fills its container |
variant |
variant |
`primary | `secondary |
`primary |
Its look |
className |
class_ |
string |
Added after HeroUI’s classes | |
children |
children |
elements | Its label, trigger, description and popover |
Select.Trigger, Select.Popover
Section titled “Select.Trigger, Select.Popover”| React | solidtype | Type | Description |
|---|---|---|---|
placement |
placement |
`top | `bottom | `left | `right |
The popover’s side, bottom by default |
className |
class_ |
string |
Added after HeroUI’s classes |
children |
children |
elements | What it holds |
Select.Value
Section titled “Select.Value”| React | solidtype | Type | Description |
|---|---|---|---|
className |
class_ |
string |
Added after HeroUI’s classes |
children |
children |
string array accessor -> element |
What it draws while something is chosen, given the ids chosen |
Select.Indicator, Select.Clear_button
Section titled “Select.Indicator, Select.Clear_button”| React | solidtype | Type | Description |
|---|---|---|---|
className |
class_ |
string |
Added after HeroUI’s classes |
children |
children |
elements | An icon of its own |
onClick |
on_click |
Dom.mouseEvent -> unit |
The clear button’s, told after it clears |
List_box.Load_more_item
Section titled “List_box.Load_more_item”| React | solidtype | Type | Default | Description |
|---|---|---|---|---|
isLoading |
is_loading |
bool |
false |
Whether more are loading, while its children show |
onLoadMore |
on_load_more |
unit -> unit |
Asked for more as the list scrolls to it | |
scrollOffset |
scroll_offset |
float |
1 | How many of the list’s heights before its end it asks |
children |
children |
elements | What shows while more load |
Beside React
Section titled “Beside React”Original HeroUI documentation: Select.
The same HeroUI Select twice, under the same props: in solidtype on the left, in React on the right. Below them, every attribute of each trigger: a marked row is one they disagree on, and a dimmed row is a framework’s own, which no style reads.
| attribute | solidtype | React |
|---|
