Autocomplete
HeroUIA select whose popover filters its list by a search field, HeroUI's on Kobalte's combo box.
Solidtype_heroui.Autocomplete is a select whose popover holds a search
field that filters its list, on Kobalte’s Combobox, with the classes
HeroUI’s own autocompleteVariants gives. Its search is the Search_field
inside its Autocomplete.Filter, and its list the List_box beside it, as
in HeroUI; Label, Description and Field_error inside it name, describe
and qualify it.
HeroUI’s example draws the states chosen as tags, with a TagGroup, which is not ported yet; here they are listed as the value draws them.
module Autocomplete = Solidtype_heroui.Autocompletemodule Empty_state = Solidtype_heroui.Empty_statemodule Label = Solidtype_heroui.Labelmodule List_box = Solidtype_heroui.List_boxmodule Search_field = Solidtype_heroui.Search_field
let make () = <Autocomplete class_="w-[256px]" placeholder="Select states" selection_mode=`multiple> <Label>"States to Visit"</Label> <Autocomplete.Trigger> <Autocomplete.Value /> <Autocomplete.Indicator /> </Autocomplete.Trigger> <Autocomplete.Popover> <Autocomplete.Filter> <Search_field aria_label="Search options" name="search" variant=`secondary> <Search_field.Group> <Search_field.Search_icon /> <Search_field.Input placeholder="Search..." /> <Search_field.Clear_button /> </Search_field.Group> </Search_field> <List_box render_empty_state=(fun _ -> <Empty_state>"No results found"</Empty_state>) selection_mode=`multiple> <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> </Autocomplete.Filter> </Autocomplete.Popover> </Autocomplete>Anatomy
Section titled “Anatomy”<Autocomplete> <Label>...</Label> <Autocomplete.Trigger> <Autocomplete.Value /> <Autocomplete.Clear_button /> <Autocomplete.Indicator /> </Autocomplete.Trigger> <Description>...</Description> <Autocomplete.Popover> <Autocomplete.Filter> <Search_field> <Search_field.Group> <Search_field.Search_icon /> <Search_field.Input /> </Search_field.Group> </Search_field> <List_box> <List_box.Item id="...">...</List_box.Item> </List_box> </Autocomplete.Filter> </Autocomplete.Popover></Autocomplete>Examples
Section titled “Examples”Variants
Section titled “Variants”Single Select Variants
Multiple Select Variants
module S = Solidtype.Solidmodule Jsx = Solidtype.Jsxmodule Autocomplete = Solidtype_heroui.Autocompletemodule Empty_state = Solidtype_heroui.Empty_statemodule Label = Solidtype_heroui.Labelmodule List_box = Solidtype_heroui.List_boxmodule Search_field = Solidtype_heroui.Search_field
let items = [| ("option1", "Option 1"); ("option2", "Option 2"); ("option3", "Option 3"); ("option4", "Option 4"); |]
let variant ~label ~variant ~mode = let selected, set_selected = S.create_signal [||] in <Autocomplete class_="w-[256px]" placeholder=(fun () -> match mode with | `single -> "Select one" | `multiple -> "Select options") selection_mode=(fun () -> mode) value=(fun () -> S.get selected) variant=(fun () -> variant) on_change=(S.set set_selected)> <Label>(fun () -> Jsx.string label)</Label> <Autocomplete.Trigger> <Autocomplete.Value /> <Autocomplete.Clear_button /> <Autocomplete.Indicator /> </Autocomplete.Trigger> <Autocomplete.Popover> <Autocomplete.Filter> <Search_field aria_label="Search options" name="search" variant=`secondary> <Search_field.Group> <Search_field.Search_icon /> <Search_field.Input placeholder="Search..." /> <Search_field.Clear_button /> </Search_field.Group> </Search_field> <List_box render_empty_state=(fun _ -> <Empty_state>"No results found"</Empty_state>) selection_mode=(fun () -> (mode :> List_box.selection_mode))> <Solidtype.For each=(fun () -> items)> (fun (id, name) _ -> <List_box.Item id=(fun () -> id) text_value=(fun () -> name)> (fun () -> Jsx.string name) <List_box.Item_indicator /> </List_box.Item>) </Solidtype.For> </List_box> </Autocomplete.Filter> </Autocomplete.Popover> </Autocomplete>
let make () = <div class_="flex flex-col gap-8"> <div class_="flex flex-col gap-4"> <h3 class_="text-lg font-semibold">"Single Select Variants"</h3> <div class_="flex flex-col gap-4"> (fun () -> Jsx.element (variant ~label:"Primary variant" ~variant:`primary ~mode:`single)) (fun () -> Jsx.element (variant ~label:"Secondary variant" ~variant:`secondary ~mode:`single)) </div> </div> <div class_="flex flex-col gap-4"> <h3 class_="text-lg font-semibold">"Multiple Select Variants"</h3> <div class_="flex flex-col gap-4"> (fun () -> Jsx.element (variant ~label:"Primary variant" ~variant:`primary ~mode:`multiple)) (fun () -> Jsx.element (variant ~label:"Secondary variant" ~variant:`secondary ~mode:`multiple)) </div> </div> </div>Full Width
Section titled “Full Width”module Autocomplete = Solidtype_heroui.Autocompletemodule Empty_state = Solidtype_heroui.Empty_statemodule Label = Solidtype_heroui.Labelmodule List_box = Solidtype_heroui.List_boxmodule Search_field = Solidtype_heroui.Search_field
let make () = <div class_="w-[400px] space-y-4"> <Autocomplete full_width=true placeholder="Select one" variant=`secondary> <Label>"State"</Label> <Autocomplete.Trigger> <Autocomplete.Value /> <Autocomplete.Clear_button /> <Autocomplete.Indicator /> </Autocomplete.Trigger> <Autocomplete.Popover> <Autocomplete.Filter> <Search_field aria_label="Search states" name="search" variant=`secondary> <Search_field.Group> <Search_field.Search_icon /> <Search_field.Input placeholder="Search states..." /> <Search_field.Clear_button /> </Search_field.Group> </Search_field> <List_box render_empty_state=(fun _ -> <Empty_state>"No results found"</Empty_state>)> <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> </Autocomplete.Filter> </Autocomplete.Popover> </Autocomplete> </div>With Description
Section titled “With Description”module Autocomplete = Solidtype_heroui.Autocompletemodule Empty_state = Solidtype_heroui.Empty_statemodule Label = Solidtype_heroui.Labelmodule List_box = Solidtype_heroui.List_boxmodule Search_field = Solidtype_heroui.Search_fieldmodule Description = Solidtype_heroui.Description
let make () = <Autocomplete class_="w-[256px]" placeholder="Select one"> <Label>"State"</Label> <Autocomplete.Trigger> <Autocomplete.Value /> <Autocomplete.Clear_button /> <Autocomplete.Indicator /> </Autocomplete.Trigger> <Description>"Select your state of residence"</Description> <Autocomplete.Popover> <Autocomplete.Filter> <Search_field aria_label="Search states" name="search" variant=`secondary> <Search_field.Group> <Search_field.Search_icon /> <Search_field.Input placeholder="Search states..." /> <Search_field.Clear_button /> </Search_field.Group> </Search_field> <List_box render_empty_state=(fun _ -> <Empty_state>"No results found"</Empty_state>)> <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> </Autocomplete.Filter> </Autocomplete.Popover> </Autocomplete>Required
Section titled “Required”HeroUI’s required autocomplete 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 autocomplete is invalid once a submit finds it empty.
module S = Solidtype.Solidmodule Autocomplete = Solidtype_heroui.Autocompletemodule Button = Solidtype_heroui.Buttonmodule Empty_state = Solidtype_heroui.Empty_statemodule Field_error = Solidtype_heroui.Field_errormodule Form = Solidtype_heroui.Formmodule Label = Solidtype_heroui.Labelmodule List_box = Solidtype_heroui.List_boxmodule Search_field = Solidtype_heroui.Search_field
external prevent_default : Dom.event -> unit = "preventDefault" [@@mel.send]external alert : string -> unit = "alert" [@@mel.scope "window"]
let make () = let state, set_state = S.create_signal [||] in (* A required autocomplete 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 () = S.get tried && Array.length (S.get state) = 0 in <Form class_="flex w-[256px] flex-col gap-4" on_submit=(fun e -> prevent_default e; S.set set_tried true; if Array.length (S.get state) > 0 then alert "Form submitted successfully!")> <Autocomplete is_required=true is_invalid=(fun () -> missing ()) class_="w-full" name="state" placeholder="Select one" on_change=(S.set set_state)> <Label>"State"</Label> <Autocomplete.Trigger> <Autocomplete.Value /> <Autocomplete.Clear_button /> <Autocomplete.Indicator /> </Autocomplete.Trigger> <Autocomplete.Popover> <Autocomplete.Filter> <Search_field aria_label="Search states" name="search" variant=`secondary> <Search_field.Group> <Search_field.Search_icon /> <Search_field.Input placeholder="Search states..." /> <Search_field.Clear_button /> </Search_field.Group> </Search_field> <List_box render_empty_state=(fun _ -> <Empty_state>"No results found"</Empty_state>)> <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> </Autocomplete.Filter> </Autocomplete.Popover> <Field_error>"Please select an item in the list."</Field_error> </Autocomplete> <Button type_=`submit>"Submit"</Button> </Form>Disabled
Section titled “Disabled”module Autocomplete = Solidtype_heroui.Autocompletemodule Empty_state = Solidtype_heroui.Empty_statemodule Label = Solidtype_heroui.Labelmodule List_box = Solidtype_heroui.List_boxmodule Search_field = Solidtype_heroui.Search_field
let make () = <Autocomplete is_disabled=true class_="w-[256px]" default_value=(fun () -> [| "california" |]) placeholder="Select one"> <Label>"State"</Label> <Autocomplete.Trigger> <Autocomplete.Value /> <Autocomplete.Clear_button /> <Autocomplete.Indicator /> </Autocomplete.Trigger> <Autocomplete.Popover> <Autocomplete.Filter> <Search_field aria_label="Search states" name="search" variant=`secondary> <Search_field.Group> <Search_field.Search_icon /> <Search_field.Input placeholder="Search states..." /> <Search_field.Clear_button /> </Search_field.Group> </Search_field> <List_box render_empty_state=(fun _ -> <Empty_state>"No results found"</Empty_state>)> <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> </Autocomplete.Filter> </Autocomplete.Popover> </Autocomplete>With Disabled Options
Section titled “With Disabled Options”module Autocomplete = Solidtype_heroui.Autocompletemodule Empty_state = Solidtype_heroui.Empty_statemodule Label = Solidtype_heroui.Labelmodule List_box = Solidtype_heroui.List_boxmodule Search_field = Solidtype_heroui.Search_field
let make () = <Autocomplete class_="w-[256px]" disabled_keys=(fun () -> [| "cat"; "kangaroo" |]) placeholder="Select an animal"> <Label>"Animal"</Label> <Autocomplete.Trigger> <Autocomplete.Value /> <Autocomplete.Clear_button /> <Autocomplete.Indicator /> </Autocomplete.Trigger> <Autocomplete.Popover> <Autocomplete.Filter> <Search_field aria_label="Search animals" name="search" variant=`secondary> <Search_field.Group> <Search_field.Search_icon /> <Search_field.Input placeholder="Search animals..." /> <Search_field.Clear_button /> </Search_field.Group> </Search_field> <List_box render_empty_state=(fun _ -> <Empty_state>"No results found"</Empty_state>)> <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> </Autocomplete.Filter> </Autocomplete.Popover> </Autocomplete>Allows Empty Collection
Section titled “Allows Empty Collection”module Autocomplete = Solidtype_heroui.Autocompletemodule Empty_state = Solidtype_heroui.Empty_statemodule Label = Solidtype_heroui.Labelmodule List_box = Solidtype_heroui.List_boxmodule Search_field = Solidtype_heroui.Search_field
let make () = <Autocomplete allows_empty_collection=true class_="w-[256px]" placeholder="Select one"> <Label>"State"</Label> <Autocomplete.Trigger> <Autocomplete.Value /> <Autocomplete.Clear_button /> <Autocomplete.Indicator /> </Autocomplete.Trigger> <Autocomplete.Popover> <Autocomplete.Filter> <Search_field aria_label="Search states" name="search" variant=`secondary> <Search_field.Group> <Search_field.Search_icon /> <Search_field.Input placeholder="Search states..." /> <Search_field.Clear_button /> </Search_field.Group> </Search_field> <List_box render_empty_state=(fun _ -> <Empty_state>"No results found"</Empty_state>) /> </Autocomplete.Filter> </Autocomplete.Popover> </Autocomplete>With Sections
Section titled “With Sections”module Autocomplete = Solidtype_heroui.Autocompletemodule Empty_state = Solidtype_heroui.Empty_statemodule Label = Solidtype_heroui.Labelmodule List_box = Solidtype_heroui.List_boxmodule Search_field = Solidtype_heroui.Search_fieldmodule Header = Solidtype_heroui.Headermodule Separator = Solidtype_heroui.Separator
let make () = <Autocomplete class_="w-[256px]" placeholder="Select a country"> <Label>"Country"</Label> <Autocomplete.Trigger> <Autocomplete.Value /> <Autocomplete.Clear_button /> <Autocomplete.Indicator /> </Autocomplete.Trigger> <Autocomplete.Popover> <Autocomplete.Filter> <Search_field aria_label="Search countries" name="search" variant=`secondary> <Search_field.Group> <Search_field.Search_icon /> <Search_field.Input placeholder="Search countries..." /> <Search_field.Clear_button /> </Search_field.Group> </Search_field> <List_box render_empty_state=(fun _ -> <Empty_state>"No results found"</Empty_state>)> <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> </Autocomplete.Filter> </Autocomplete.Popover> </Autocomplete>Multiple Select
Section titled “Multiple Select”module Autocomplete = Solidtype_heroui.Autocompletemodule Empty_state = Solidtype_heroui.Empty_statemodule Label = Solidtype_heroui.Labelmodule List_box = Solidtype_heroui.List_boxmodule Search_field = Solidtype_heroui.Search_field
let make () = <Autocomplete class_="w-[256px]" placeholder="Select states" selection_mode=`multiple> <Label>"States"</Label> <Autocomplete.Trigger> <Autocomplete.Value /> <Autocomplete.Clear_button /> <Autocomplete.Indicator /> </Autocomplete.Trigger> <Autocomplete.Popover> <Autocomplete.Filter> <Search_field aria_label="Search options" name="search" variant=`secondary> <Search_field.Group> <Search_field.Search_icon /> <Search_field.Input placeholder="Search..." /> <Search_field.Clear_button /> </Search_field.Group> </Search_field> <List_box render_empty_state=(fun _ -> <Empty_state>"No results found"</Empty_state>) selection_mode=`multiple> <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> </Autocomplete.Filter> </Autocomplete.Popover> </Autocomplete>Controlled
Section titled “Controlled”The ids chosen are value, an array, as a select’s are.
Selected: California
module S = Solidtype.Solidmodule Jsx = Solidtype.Jsxmodule Autocomplete = Solidtype_heroui.Autocompletemodule Empty_state = Solidtype_heroui.Empty_statemodule Label = Solidtype_heroui.Labelmodule List_box = Solidtype_heroui.List_boxmodule Search_field = Solidtype_heroui.Search_field
let states = [| ("california", "California"); ("texas", "Texas"); ("florida", "Florida"); ("new-york", "New York"); ("illinois", "Illinois"); ("pennsylvania", "Pennsylvania"); |]
let make () = let state, set_state = S.create_signal [| "california" |] in let name () = match S.get state with | [| key |] -> ( match Array.find_opt (fun (id, _) -> String.equal id key) states with | Some (_, name) -> name | None -> "None") | _ -> "None" in <div class_="space-y-4"> <Autocomplete class_="w-[256px]" placeholder="Select a state" value=(fun () -> S.get state) on_change=(S.set set_state)> <Label>"State (controlled)"</Label> <Autocomplete.Trigger> <Autocomplete.Value /> <Autocomplete.Clear_button /> <Autocomplete.Indicator /> </Autocomplete.Trigger> <Autocomplete.Popover> <Autocomplete.Filter> <Search_field aria_label="Search states" name="search" variant=`secondary> <Search_field.Group> <Search_field.Search_icon /> <Search_field.Input placeholder="Search states..." /> <Search_field.Clear_button /> </Search_field.Group> </Search_field> <List_box render_empty_state=(fun _ -> <Empty_state>"No results found"</Empty_state>)> <Solidtype.For each=(fun () -> states)> (fun (id, name) _ -> <List_box.Item id=(fun () -> id) text_value=(fun () -> name)> (fun () -> Jsx.string name) <List_box.Item_indicator /> </List_box.Item>) </Solidtype.For> </List_box> </Autocomplete.Filter> </Autocomplete.Popover> </Autocomplete> <p class_="text-sm text-muted"> (fun () -> Jsx.string ("Selected: " ^ name ())) </p> </div>Controlled Multiple
Section titled “Controlled Multiple”Selected: California, Texas
module S = Solidtype.Solidmodule Jsx = Solidtype.Jsxmodule Autocomplete = Solidtype_heroui.Autocompletemodule Empty_state = Solidtype_heroui.Empty_statemodule Label = Solidtype_heroui.Labelmodule List_box = Solidtype_heroui.List_boxmodule Search_field = Solidtype_heroui.Search_field
let states = [| ("california", "California"); ("texas", "Texas"); ("florida", "Florida"); ("new-york", "New York"); ("illinois", "Illinois"); ("pennsylvania", "Pennsylvania"); |]
let make () = let selected, set_selected = S.create_signal [| "california"; "texas" |] in let names () = S.get selected |> Array.to_list |> List.filter_map (fun key -> Option.map snd (Array.find_opt (fun (id, _) -> String.equal id key) states)) in <div class_="space-y-4"> <Autocomplete class_="w-[256px]" placeholder="Select states" selection_mode=`multiple value=(fun () -> S.get selected) on_change=(S.set set_selected)> <Label>"States (controlled multiple)"</Label> <Autocomplete.Trigger> <Autocomplete.Value /> <Autocomplete.Clear_button /> <Autocomplete.Indicator /> </Autocomplete.Trigger> <Autocomplete.Popover> <Autocomplete.Filter> <Search_field aria_label="Search states" name="search" variant=`secondary> <Search_field.Group> <Search_field.Search_icon /> <Search_field.Input placeholder="Search states..." /> <Search_field.Clear_button /> </Search_field.Group> </Search_field> <List_box render_empty_state=(fun _ -> <Empty_state>"No results found"</Empty_state>) selection_mode=`multiple> <Solidtype.For each=(fun () -> states)> (fun (id, name) _ -> <List_box.Item id=(fun () -> id) text_value=(fun () -> name)> (fun () -> Jsx.string name) <List_box.Item_indicator /> </List_box.Item>) </Solidtype.For> </List_box> </Autocomplete.Filter> </Autocomplete.Popover> </Autocomplete> <p class_="text-sm text-muted"> (fun () -> Jsx.string ("Selected: " ^ match names () with | [] -> "None" | names -> String.concat ", " names)) </p> </div>Controlled Open State
Section titled “Controlled Open State”Autocomplete is closed
module S = Solidtype.Solidmodule Jsx = Solidtype.Jsxmodule Autocomplete = Solidtype_heroui.Autocompletemodule Button = Solidtype_heroui.Buttonmodule Empty_state = Solidtype_heroui.Empty_statemodule Label = Solidtype_heroui.Labelmodule List_box = Solidtype_heroui.List_boxmodule Search_field = Solidtype_heroui.Search_field
let states = [| ("florida", "Florida"); ("delaware", "Delaware"); ("california", "California"); ("texas", "Texas"); ("new-york", "New York"); ("washington", "Washington"); |]
let make () = let is_open, set_open = S.create_signal false in <div class_="space-y-4"> <Autocomplete class_="w-[256px]" is_open=(fun () -> S.get is_open) placeholder="Select one" on_open_change=(S.set set_open)> <Label>"State"</Label> <Autocomplete.Trigger> <Autocomplete.Value /> <Autocomplete.Clear_button /> <Autocomplete.Indicator /> </Autocomplete.Trigger> <Autocomplete.Popover> <Autocomplete.Filter> <Search_field aria_label="Search states" name="search" variant=`secondary> <Search_field.Group> <Search_field.Search_icon /> <Search_field.Input placeholder="Search states..." /> <Search_field.Clear_button /> </Search_field.Group> </Search_field> <List_box render_empty_state=(fun _ -> <Empty_state>"No results found"</Empty_state>)> <Solidtype.For each=(fun () -> states)> (fun (id, name) _ -> <List_box.Item id=(fun () -> id) text_value=(fun () -> name)> (fun () -> Jsx.string name) <List_box.Item_indicator /> </List_box.Item>) </Solidtype.For> </List_box> </Autocomplete.Filter> </Autocomplete.Popover> </Autocomplete> <Button on_click=(fun _ -> S.set set_open (not (S.get is_open)))> (fun () -> Jsx.string ((if S.get is_open then "Close" else "Open") ^ " Autocomplete")) </Button> <p class_="text-sm text-muted"> (fun () -> Jsx.string ("Autocomplete is " ^ if S.get is_open then "open" else "closed")) </p> </div>Asynchronous Filtering
Section titled “Asynchronous Filtering”HeroUI’s example searches a server for each text typed; here the same names
are searched after the same wait. The filter’s input_value and
on_input_change hold the search’s text.
module S = Solidtype.Solidmodule Jsx = Solidtype.Jsxmodule Autocomplete = Solidtype_heroui.Autocompletemodule Empty_state = Solidtype_heroui.Empty_statemodule Label = Solidtype_heroui.Labelmodule List_box = Solidtype_heroui.List_boxmodule Search_field = Solidtype_heroui.Search_field
(* The first two pages of https://swapi.py4e.com/api/people/, which HeroUI's example searches, here searched after the same wait. *)let characters = [| "Luke Skywalker"; "C-3PO"; "R2-D2"; "Darth Vader"; "Leia Organa"; "Owen Lars"; "Beru Whitesun lars"; "R5-D4"; "Biggs Darklighter"; "Obi-Wan Kenobi"; "Anakin Skywalker"; "Wilhuff Tarkin"; "Chewbacca"; "Han Solo"; "Greedo"; "Jabba Desilijic Tiure"; "Wedge Antilles"; "Jek Tono Porkins"; "Yoda"; "Palpatine"; |]
(* How long the fetch it stands in for takes. *)let load_ms = 400
(* Whether [part] is in [name], whatever their case, as the search finds it. *)let holds ~part name = let name = String.lowercase_ascii name and part = String.lowercase_ascii part in let n = String.length part in let rec from i = i + n <= String.length name && (String.equal (String.sub name i n) part || from (i + 1)) in from 0
let make () = let filter_text, set_filter_text = S.create_signal "" in let found, set_found = S.create_signal characters in let search text = S.set set_filter_text text; let timer = Js.Global.setTimeout ~f:(fun () -> S.set set_found (Array.of_list (List.filter (fun name -> holds ~part:text name) (Array.to_list characters)))) load_ms in S.on_cleanup (fun () -> Js.Global.clearTimeout timer) in <Autocomplete allows_empty_collection=true class_="w-[256px]" placeholder="Search..."> <Label>"Search a Star Wars characters"</Label> <Autocomplete.Trigger> <Autocomplete.Value /> <Autocomplete.Clear_button /> <Autocomplete.Indicator /> </Autocomplete.Trigger> <Autocomplete.Popover> <Autocomplete.Filter input_value=(fun () -> S.get filter_text) on_input_change=search> <Search_field aria_label="Search characters" name="search" variant=`secondary> <Search_field.Group> <Search_field.Search_icon /> <Search_field.Input placeholder="Search characters..." /> <Search_field.Clear_button /> </Search_field.Group> </Search_field> <List_box class_="max-h-[420px] overflow-y-auto" render_empty_state=(fun _ -> <Empty_state>"No results found"</Empty_state>)> <Solidtype.For each=(fun () -> S.get found)> (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> </Autocomplete.Filter> </Autocomplete.Popover> </Autocomplete>Custom Indicator
Section titled “Custom Indicator”module Autocomplete = Solidtype_heroui.Autocompletemodule Empty_state = Solidtype_heroui.Empty_statemodule Label = Solidtype_heroui.Labelmodule List_box = Solidtype_heroui.List_boxmodule Search_field = Solidtype_heroui.Search_field
let make () = <Autocomplete class_="w-[256px]" placeholder="Select one"> <Label>"State"</Label> <Autocomplete.Trigger> <Autocomplete.Value /> <Autocomplete.Clear_button /> <Autocomplete.Indicator class_="size-3"> <Gravity.Chevrons_expand_vertical /> </Autocomplete.Indicator> </Autocomplete.Trigger> <Autocomplete.Popover> <Autocomplete.Filter> <Search_field aria_label="Search states" name="search" variant=`secondary> <Search_field.Group> <Search_field.Search_icon /> <Search_field.Input placeholder="Search states..." /> <Search_field.Clear_button /> </Search_field.Group> </Search_field> <List_box render_empty_state=(fun _ -> <Empty_state>"No results found"</Empty_state>)> <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> </Autocomplete.Filter> </Autocomplete.Popover> </Autocomplete>Custom Value
Section titled “Custom Value”Autocomplete.Value’s children are a function of the ids chosen, drawn
while one is; the autocomplete draws its placeholder while none is.
module S = Solidtype.Solidmodule Jsx = Solidtype.Jsxmodule Autocomplete = Solidtype_heroui.Autocompletemodule Description = Solidtype_heroui.Descriptionmodule Empty_state = Solidtype_heroui.Empty_statemodule Label = Solidtype_heroui.Labelmodule List_box = Solidtype_heroui.List_boxmodule Search_field = Solidtype_heroui.Search_field
type currency = { code : string; id : string; name : string; symbol : string }
let currencies = [| { code = "USD"; id = "usd"; name = "US Dollar"; symbol = "$" }; { code = "EUR"; id = "eur"; name = "Euro"; symbol = {js|€|js} }; { code = "GBP"; id = "gbp"; name = "British Pound"; symbol = {js|£|js} }; { code = "JPY"; id = "jpy"; name = "Japanese Yen"; symbol = {js|¥|js} }; { code = "CHF"; id = "chf"; name = "Swiss Franc"; symbol = {js|₣|js} }; |]
let make () = <Autocomplete class_="w-[256px]" default_value=(fun () -> [| "usd" |]) placeholder="Select a currency"> <Label>"Currency"</Label> <Autocomplete.Trigger> <Autocomplete.Value> (fun keys -> <span class_="contents"> (fun () -> match S.get keys with | [| key |] -> ( match Array.find_opt (fun c -> String.equal c.id key) currencies with | Some c -> Jsx.element <span class_="flex min-w-0 items-center gap-1.5"> <span class_="font-medium"> (fun () -> Jsx.string c.symbol) </span> <span>(fun () -> Jsx.string c.code)</span> <span class_="truncate text-muted"> (fun () -> Jsx.string c.name) </span> </span> | None -> Jsx.element Jsx.nothing) | _ -> Jsx.element Jsx.nothing) </span>) </Autocomplete.Value> <Autocomplete.Indicator /> </Autocomplete.Trigger> <Autocomplete.Popover> <Autocomplete.Filter> <Search_field aria_label="Search currencies" name="search" variant=`secondary> <Search_field.Group> <Search_field.Search_icon /> <Search_field.Input placeholder="Search currencies..." /> <Search_field.Clear_button /> </Search_field.Group> </Search_field> <List_box render_empty_state=(fun _ -> <Empty_state>"No results found"</Empty_state>)> <Solidtype.For each=(fun () -> currencies)> (fun c _ -> <List_box.Item id=(fun () -> c.id) text_value=(fun () -> c.code ^ " " ^ c.name)> <div class_="flex flex-col"> <Label>(fun () -> Jsx.string c.code)</Label> <Description>(fun () -> Jsx.string c.name)</Description> </div> <List_box.Item_indicator /> </List_box.Item>) </Solidtype.For> </List_box> </Autocomplete.Filter> </Autocomplete.Popover> </Autocomplete>In Surface
Section titled “In Surface”module S = Solidtype.Solidmodule Autocomplete = Solidtype_heroui.Autocompletemodule Empty_state = Solidtype_heroui.Empty_statemodule Label = Solidtype_heroui.Labelmodule List_box = Solidtype_heroui.List_boxmodule Search_field = Solidtype_heroui.Search_fieldmodule Surface = Solidtype_heroui.Surface
let make () = let selected, set_selected = S.create_signal [||] in <Surface class_="w-[320px] rounded-3xl p-6"> <Autocomplete class_="w-full" placeholder="Select one" value=(fun () -> S.get selected) variant=`secondary on_change=(S.set set_selected)> <Label>"State"</Label> <Autocomplete.Trigger> <Autocomplete.Value /> <Autocomplete.Clear_button /> <Autocomplete.Indicator /> </Autocomplete.Trigger> <Autocomplete.Popover> <Autocomplete.Filter> <Search_field aria_label="Search states" name="search" variant=`secondary> <Search_field.Group> <Search_field.Search_icon /> <Search_field.Input placeholder="Search states..." /> <Search_field.Clear_button /> </Search_field.Group> </Search_field> <List_box render_empty_state=(fun _ -> <Empty_state>"No results found"</Empty_state>)> <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> </Autocomplete.Filter> </Autocomplete.Popover> </Autocomplete> </Surface>Virtualization
Section titled “Virtualization”HeroUI’s Virtualization example draws a long list by React Aria’s
Virtualizer, which a List_box has no counterpart of yet: it draws every
option.
Advanced Examples
Section titled “Advanced Examples”User Selection
Section titled “User Selection”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 Autocomplete = Solidtype_heroui.Autocompletemodule Empty_state = Solidtype_heroui.Empty_statemodule Search_field = Solidtype_heroui.Search_field
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 () = <Autocomplete class_="w-[256px]" placeholder="Select a user"> <Label>"User"</Label> <Autocomplete.Trigger> <Autocomplete.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>) </Autocomplete.Value> <Autocomplete.Clear_button /> <Autocomplete.Indicator /> </Autocomplete.Trigger> <Autocomplete.Popover> <Autocomplete.Filter> <Search_field aria_label="Search users" name="search" variant=`secondary> <Search_field.Group> <Search_field.Search_icon /> <Search_field.Input placeholder="Search users..." /> <Search_field.Clear_button /> </Search_field.Group> </Search_field> <List_box render_empty_state=(fun _ -> <Empty_state>"No results found"</Empty_state>)> <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> </Autocomplete.Filter> </Autocomplete.Popover> </Autocomplete>Location Search
Section titled “Location Search”module S = Solidtype.Solidmodule Jsx = Solidtype.Jsxmodule Autocomplete = Solidtype_heroui.Autocompletemodule Description = Solidtype_heroui.Descriptionmodule Empty_state = Solidtype_heroui.Empty_statemodule Label = Solidtype_heroui.Labelmodule List_box = Solidtype_heroui.List_boxmodule Search_field = Solidtype_heroui.Search_field
type city = { name : string; country : string }
let cities = [| { country = "USA"; name = "New York" }; { country = "USA"; name = "Los Angeles" }; { country = "USA"; name = "Chicago" }; { country = "UK"; name = "London" }; { country = "France"; name = "Paris" }; { country = "Japan"; name = "Tokyo" }; { country = "Australia"; name = "Sydney" }; { country = "Canada"; name = "Toronto" }; { country = "Germany"; name = "Berlin" }; { country = "Spain"; name = "Madrid" }; |]
(* How long the search it stands in for takes. *)let search_ms = 300
(* Whether [part] is in [text], whatever their case. *)let holds ~part text = let text = String.lowercase_ascii text and part = String.lowercase_ascii part in let n = String.length part in let rec from i = i + n <= String.length text && (String.equal (String.sub text i n) part || from (i + 1)) in from 0
let make () = let selected, set_selected = S.create_signal [||] in let loading, set_loading = S.create_signal false in (* HeroUI's example stands in for a search that takes a while. *) let filter text typed = String.equal typed "" || (S.set set_loading true; let (_ : Js.Global.timeoutId) = Js.Global.setTimeout ~f:(fun () -> S.set set_loading false) search_ms in holds ~part:typed text) in <Autocomplete class_="w-[256px]" placeholder="Search for a city" value=(fun () -> S.get selected) on_change=(S.set set_selected)> <Label>"City"</Label> <Autocomplete.Trigger> <Autocomplete.Value /> <Autocomplete.Clear_button /> <Autocomplete.Indicator /> </Autocomplete.Trigger> <Autocomplete.Popover> <Autocomplete.Filter filter> <Search_field aria_label="Search cities" name="search" variant=`secondary> <Search_field.Group> <Search_field.Search_icon /> <Search_field.Input placeholder="Search cities..." /> <Search_field.Clear_button /> </Search_field.Group> </Search_field> <List_box render_empty_state=(fun _ -> <Empty_state> (fun () -> Jsx.string (if S.get loading then "Searching..." else "No cities found")) </Empty_state>)> <Solidtype.For each=(fun () -> cities)> (fun city _ -> <List_box.Item id=(fun () -> city.name) text_value=(fun () -> city.name)> <div class_="flex flex-col"> <Label>(fun () -> Jsx.string city.name)</Label> <Description>(fun () -> Jsx.string city.country)</Description> </div> <List_box.Item_indicator /> </List_box.Item>) </Solidtype.For> </List_box> </Autocomplete.Filter> </Autocomplete.Popover> </Autocomplete>User Selection Multiple, Tag Group Selection, Email Recipients
Section titled “User Selection Multiple, Tag Group Selection, Email Recipients”These draw the options chosen as tags, with HeroUI’s TagGroup, which is not ported yet.
Customization
Section titled “Customization”Tailwind CSS
Section titled “Tailwind CSS”HeroUI’s Tailwind example draws the people chosen as tags, with a TagGroup,
which is not ported yet; class_ is added after HeroUI’s classes on every
part, as the examples above show.
Global CSS
Section titled “Global CSS”HeroUI’s classes are global, so a stylesheet restyles every one, as with HeroUI in React:
@layer components { .autocomplete__trigger { @apply rounded-lg border border-border bg-surface; }
.autocomplete__popover { @apply rounded-xl; }}Styling Reference
Section titled “Styling Reference”CSS Classes
Section titled “CSS Classes”.autocomplete,.autocomplete--primary,.autocomplete--secondary,.autocomplete--full-width.autocomplete__trigger,.autocomplete__value,.autocomplete__clear-button,.autocomplete__indicator,.autocomplete__popover
Interactive States
Section titled “Interactive States”- Open:
[data-open="true"]on the autocomplete and its indicator - Focus:
[data-focused="true"]on the autocomplete while its button has the focus;[data-focus-within="true"]on its trigger - Hover:
[data-hovered="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 autocomplete - Entering and Exiting:
[data-entering="true"],[data-exiting="true"]on the popover
How it is made
Section titled “How it is made”Kobalte’s combo box filters its options by the search’s text, whatever its
case or accents, or by the filter given, and keeps the focus in the search
while the arrows move through the list, as React Aria’s autocomplete does.
Its list is the List_box beside the search, whose options join the
autocomplete while it is closed too, so its value shows the option chosen;
the search moves into the popover each time it opens, and starts empty.
A press on the trigger, or an arrow on its button, opens the list and gives the search the focus; typing gives the first option the search keeps the focus. Enter or a press chooses: in a choice of one the list closes and the focus goes back to the button, where React Aria’s is lost to the page. While the list is open the page outside is hidden from a reader and no pointer reaches it, as React Aria’s modal popover does.
The search’s input is Kobalte’s combo box input, which tells a reader it expands and which option it holds, where React Aria’s is a search box that controls the list.
API Reference
Section titled “API Reference”Each prop beside the name HeroUI’s React component gives it.
Autocomplete
Section titled “Autocomplete”| 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 | |
allowsEmptyCollection |
allows_empty_collection |
bool |
false |
Whether it opens with no option at all |
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 |
Autocomplete.Filter
Section titled “Autocomplete.Filter”| React | solidtype | Type | Description |
|---|---|---|---|
filter |
filter |
string -> string -> bool |
Keeps an option given its text and the search’s; contains by default |
inputValue |
input_value |
string |
The search’s text, controlled |
onInputChange |
on_input_change |
string -> unit |
Told the search’s text as it changes |
children |
children |
elements | Its Search_field and List_box |
Autocomplete.Trigger, Autocomplete.Popover, Autocomplete.Indicator, Autocomplete.Clear_button
Section titled “Autocomplete.Trigger, Autocomplete.Popover, Autocomplete.Indicator, Autocomplete.Clear_button”| 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; the indicator’s own icon |
onClick |
on_click |
Dom.mouseEvent -> unit |
The clear button’s, told after it clears |
Autocomplete.Value
Section titled “Autocomplete.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 |
Beside React
Section titled “Beside React”Original HeroUI documentation: Autocomplete.
The same HeroUI Autocomplete twice, under the same props: in solidtype on the left, in React on the right. Below them, every attribute of each button: a marked row is one they disagree on, and a dimmed row is a framework’s own, which no style reads.
| attribute | solidtype | React |
|---|
