SearchField
HeroUIA search input, cleared by Escape or its button and submitted by Enter.
Solidtype_heroui.Search_field is Kobalte’s TextField.Root, with the
classes HeroUI’s own searchFieldVariants gives, whose input is a search:
Escape clears it, Enter submits it, and its clear button clears it and gives
its input the focus back, as React Aria’s does. Kobalte’s Search is a
combobox; HeroUI’s search field is a text field, which this is.
HeroUI’s examples, with HeroUI’s icons from @gravity-ui/icons.
module Label = Solidtype_heroui.Labelmodule Search_field = Solidtype_heroui.Search_field
let make () = <Search_field name="search"> <Label>"Search"</Label> <Search_field.Group> <Search_field.Search_icon /> <Search_field.Input class_="w-[280px]" placeholder="Search..." /> <Search_field.Clear_button /> </Search_field.Group> </Search_field>Anatomy
Section titled “Anatomy”<Search_field> <Label>"Search"</Label> <Search_field.Group> <Search_field.Search_icon /> <Search_field.Input placeholder="Search..." /> <Search_field.Clear_button /> </Search_field.Group> <Description>"Find a task"</Description></Search_field>Examples
Section titled “Examples”Variants
Section titled “Variants”module Label = Solidtype_heroui.Labelmodule Search_field = Solidtype_heroui.Search_field
let make () = <div class_="flex flex-col gap-4"> <Search_field name="primary-search" variant=`primary> <Label>"Primary variant"</Label> <Search_field.Group> <Search_field.Search_icon /> <Search_field.Input class_="w-[280px]" placeholder="Search..." /> <Search_field.Clear_button /> </Search_field.Group> </Search_field> <Search_field name="secondary-search" variant=`secondary> <Label>"Secondary variant"</Label> <Search_field.Group> <Search_field.Search_icon /> <Search_field.Input class_="w-[280px]" placeholder="Search..." /> <Search_field.Clear_button /> </Search_field.Group> </Search_field> </div>In Surface
Section titled “In Surface”module Description = Solidtype_heroui.Descriptionmodule Label = Solidtype_heroui.Labelmodule Search_field = Solidtype_heroui.Search_fieldmodule Surface = Solidtype_heroui.Surface
let make () = <Surface class_="flex w-full max-w-sm flex-col gap-4 rounded-3xl p-6"> <Search_field name="search" variant=`secondary> <Label>"Search"</Label> <Search_field.Group> <Search_field.Search_icon /> <Search_field.Input class_="w-full" placeholder="Search..." /> <Search_field.Clear_button /> </Search_field.Group> <Description>"Enter keywords to search"</Description> </Search_field> <Search_field name="search-2" variant=`secondary> <Label>"Advanced search"</Label> <Search_field.Group> <Search_field.Search_icon /> <Search_field.Input class_="w-full" placeholder="Advanced search..." /> <Search_field.Clear_button /> </Search_field.Group> <Description>"Use filters to refine your search"</Description> </Search_field> </Surface>With Description
Section titled “With Description”module Description = Solidtype_heroui.Descriptionmodule Label = Solidtype_heroui.Labelmodule Search_field = Solidtype_heroui.Search_field
let make () = <div class_="flex flex-col gap-4"> <Search_field name="search"> <Label>"Search products"</Label> <Search_field.Group> <Search_field.Search_icon /> <Search_field.Input class_="w-[280px]" placeholder="Search products..." /> <Search_field.Clear_button /> </Search_field.Group> <Description>"Enter keywords to search for products"</Description> </Search_field> <Search_field name="search-users"> <Label>"Search users"</Label> <Search_field.Group> <Search_field.Search_icon /> <Search_field.Input class_="w-[280px]" placeholder="Search users..." /> <Search_field.Clear_button /> </Search_field.Group> <Description>"Search by name, email, or username"</Description> </Search_field> </div>Required Field
Section titled “Required Field”module Description = Solidtype_heroui.Descriptionmodule Label = Solidtype_heroui.Labelmodule Search_field = Solidtype_heroui.Search_field
let make () = <div class_="flex flex-col gap-4"> <Search_field is_required=true name="search"> <Label>"Search"</Label> <Search_field.Group> <Search_field.Search_icon /> <Search_field.Input class_="w-[280px]" placeholder="Search..." /> <Search_field.Clear_button /> </Search_field.Group> </Search_field> <Search_field is_required=true name="search-query"> <Label>"Search query"</Label> <Search_field.Group> <Search_field.Search_icon /> <Search_field.Input class_="w-[280px]" placeholder="Enter search query..." /> <Search_field.Clear_button /> </Search_field.Group> <Description>"Minimum 3 characters required"</Description> </Search_field> </div>Disabled State
Section titled “Disabled State”module Description = Solidtype_heroui.Descriptionmodule Label = Solidtype_heroui.Labelmodule Search_field = Solidtype_heroui.Search_field
let make () = <div class_="flex flex-col gap-4"> <Search_field is_disabled=true name="search" value="Disabled search"> <Label>"Search"</Label> <Search_field.Group> <Search_field.Search_icon /> <Search_field.Input class_="w-[280px]" placeholder="Search..." /> <Search_field.Clear_button /> </Search_field.Group> <Description>"This search field is disabled"</Description> </Search_field> <Search_field is_disabled=true name="search-empty"> <Label>"Search"</Label> <Search_field.Group> <Search_field.Search_icon /> <Search_field.Input class_="w-[280px]" placeholder="Search..." /> <Search_field.Clear_button /> </Search_field.Group> <Description>"This search field is disabled"</Description> </Search_field> </div>Full Width
Section titled “Full Width”module Label = Solidtype_heroui.Labelmodule Search_field = Solidtype_heroui.Search_field
let make () = <div class_="w-[400px] space-y-4"> <Search_field full_width=true name="search"> <Label>"Search"</Label> <Search_field.Group> <Search_field.Search_icon /> <Search_field.Input placeholder="Search..." /> <Search_field.Clear_button /> </Search_field.Group> </Search_field> </div>Validation
Section titled “Validation”module Field_error = Solidtype_heroui.Field_errormodule Label = Solidtype_heroui.Labelmodule Search_field = Solidtype_heroui.Search_field
let make () = <div class_="flex flex-col gap-4"> <Search_field is_invalid=true is_required=true name="search" value="ab"> <Label>"Search"</Label> <Search_field.Group> <Search_field.Search_icon /> <Search_field.Input class_="w-[280px]" placeholder="Search..." /> <Search_field.Clear_button /> </Search_field.Group> <Field_error>"Search query must be at least 3 characters"</Field_error> </Search_field> <Search_field is_invalid=true name="search-invalid" value="invalid@query"> <Label>"Search"</Label> <Search_field.Group> <Search_field.Search_icon /> <Search_field.Input class_="w-[280px]" placeholder="Search..." /> <Search_field.Clear_button /> </Search_field.Group> <Field_error>"Invalid characters in search query"</Field_error> </Search_field> </div>Controlled
Section titled “Controlled”module S = Solidtype.Solidmodule Jsx = Solidtype.Jsxmodule Button = Solidtype_heroui.Buttonmodule Description = Solidtype_heroui.Descriptionmodule Label = Solidtype_heroui.Labelmodule Search_field = Solidtype_heroui.Search_field
let make () = let value, set_value = S.create_signal "" in <div class_="flex flex-col gap-4"> <Search_field name="search" value=(fun () -> S.get value) on_change=(S.set set_value)> <Label>"Search"</Label> <Search_field.Group> <Search_field.Search_icon /> <Search_field.Input class_="w-[280px]" placeholder="Search..." /> <Search_field.Clear_button /> </Search_field.Group> <Description> (fun () -> Jsx.string ("Current value: " ^ match S.get value with "" -> "(empty)" | v -> v)) </Description> </Search_field> <div class_="flex gap-2"> <Button variant=`tertiary on_click=(fun _ -> S.set set_value "")> "Clear" </Button> <Button variant=`tertiary on_click=(fun _ -> S.set set_value "example query")> "Set example" </Button> </div> </div>Form Example
Section titled “Form Example”HeroUI’s button takes isPending while the search is sent; the port’s button has no pending state yet, so this one shows the spinner alone.
module S = Solidtype.Solidmodule Jsx = Solidtype.Jsxmodule Show = Solidtype.Showmodule Button = Solidtype_heroui.Buttonmodule Description = Solidtype_heroui.Descriptionmodule Field_error = Solidtype_heroui.Field_errormodule Form = Solidtype_heroui.Formmodule Label = Solidtype_heroui.Labelmodule Search_field = Solidtype_heroui.Search_fieldmodule Spinner = Solidtype_heroui.Spinner
external prevent_default : Dom.event -> unit = "preventDefault" [@@mel.send]
let min_length = 3
let make () = let value, set_value = S.create_signal "" in let is_submitting, set_is_submitting = S.create_signal false in let is_invalid () = let n = String.length (S.get value) in n > 0 && n < min_length in let handle_submit e = prevent_default e; if String.length (S.get value) >= min_length then ( S.set set_is_submitting true; (* Simulate API call *) ignore (Js.Global.setTimeout ~f:(fun () -> Js.log2 "Search submitted, query:" (S.get value); S.set set_value ""; S.set set_is_submitting false) 1500 : Js.Global.timeoutId)) in <Form class_="flex w-[280px] flex-col gap-4" on_submit=handle_submit> <Search_field is_required=true is_invalid=(fun () -> is_invalid ()) name="search" value=(fun () -> S.get value) on_change=(S.set set_value)> <Label>"Search products"</Label> <Search_field.Group> <Search_field.Search_icon /> <Search_field.Input class_="w-full" placeholder="Search products..." /> <Search_field.Clear_button /> </Search_field.Group> <Show when_=(fun () -> is_invalid ()) fallback=(<Description> (fun () -> Jsx.string ("Enter at least " ^ string_of_int min_length ^ " characters to search")) </Description>)> <Field_error> (fun () -> Jsx.string ("Search query must be at least " ^ string_of_int min_length ^ " characters")) </Field_error> </Show> </Search_field> <Button class_="w-full" is_disabled=(fun () -> String.length (S.get value) < min_length) type_=`submit variant=`primary> <Show when_=(fun () -> not (S.get is_submitting))>"Search"</Show> <Show when_=(fun () -> S.get is_submitting)> <Spinner color=`current size=`sm /> "Searching..." </Show> </Button> </Form>With Validation
Section titled “With Validation”module S = Solidtype.Solidmodule Show = Solidtype.Showmodule Description = Solidtype_heroui.Descriptionmodule Field_error = Solidtype_heroui.Field_errormodule Label = Solidtype_heroui.Labelmodule Search_field = Solidtype_heroui.Search_field
let make () = let value, set_value = S.create_signal "" in let is_invalid () = let n = String.length (S.get value) in n > 0 && n < 3 in <div class_="flex flex-col gap-4"> <Search_field is_required=true is_invalid=(fun () -> is_invalid ()) name="search" value=(fun () -> S.get value) on_change=(S.set set_value)> <Label>"Search"</Label> <Search_field.Group> <Search_field.Search_icon /> <Search_field.Input class_="w-[280px]" placeholder="Search..." /> <Search_field.Clear_button /> </Search_field.Group> <Show when_=(fun () -> is_invalid ()) fallback=(<Description> "Enter at least 3 characters to search" </Description>)> <Field_error>"Search query must be at least 3 characters"</Field_error> </Show> </Search_field> </div>Custom Icons
Section titled “Custom Icons”module Description = Solidtype_heroui.Descriptionmodule Label = Solidtype_heroui.Labelmodule Search_field = Solidtype_heroui.Search_field
let make () = <div class_="flex flex-col gap-4"> <Search_field name="search-custom"> <Label>"Search (Custom Icons)"</Label> <Search_field.Group> <Search_field.Search_icon><Gravity.Funnel /></Search_field.Search_icon> <Search_field.Input class_="w-[280px]" placeholder="Search..." /> <Search_field.Clear_button> <Gravity.Circle_xmark_fill /> </Search_field.Clear_button> </Search_field.Group> <Description>"Custom icon children"</Description> </Search_field> </div>With Keyboard Shortcut
Section titled “With Keyboard Shortcut”module S = Solidtype.Solidmodule Description = Solidtype_heroui.Descriptionmodule Kbd = Solidtype_heroui.Kbdmodule Label = Solidtype_heroui.Labelmodule Search_field = Solidtype_heroui.Search_field
type window
external window : window = "window"
external add_key_down : window -> (_[@mel.as "keydown"]) -> ((Dom.keyboardEvent -> unit)[@u]) -> unit = "addEventListener"[@@mel.send]
external remove_key_down : window -> (_[@mel.as "keydown"]) -> ((Dom.keyboardEvent -> unit)[@u]) -> unit = "removeEventListener"[@@mel.send]
external key : Dom.keyboardEvent -> string = "key" [@@mel.get]external shift_key : Dom.keyboardEvent -> bool = "shiftKey" [@@mel.get]external meta_key : Dom.keyboardEvent -> bool = "metaKey" [@@mel.get]external ctrl_key : Dom.keyboardEvent -> bool = "ctrlKey" [@@mel.get]external alt_key : Dom.keyboardEvent -> bool = "altKey" [@@mel.get]
external prevent_default : Dom.keyboardEvent -> unit = "preventDefault"[@@mel.send]
external query : Dom.htmlDivElement -> string -> Dom.htmlElement Js.null = "querySelector"[@@mel.send]
external active_element : Dom.htmlElement Js.null = "activeElement"[@@mel.scope "document"]
external focus : Dom.htmlElement -> unit = "focus" [@@mel.send]external blur : Dom.htmlElement -> unit = "blur" [@@mel.send]
let make () = let value, set_value = S.create_signal "" in (* The element around the field, whose input a key focuses. *) let around = ref None in let handle_key_down = fun[@u] e -> let input = Option.bind !around (fun d -> Js.Null.toOption (query d "input")) in (* Check for Shift+S *) if shift_key e && String.equal (key e) "S" && not (meta_key e || ctrl_key e || alt_key e) then ( prevent_default e; Option.iter focus input); (* Check for ESC key to blur the input *) match (key e, input, Js.Null.toOption active_element) with | "Escape", Some i, Some active when i == active -> blur i | _ -> () in S.on_mount (fun () -> add_key_down window handle_key_down; S.on_cleanup (fun () -> remove_key_down window handle_key_down)); <div class_="flex flex-col gap-4"> <div ref=(fun d -> around := Some d)> <Search_field name="search" value=(fun () -> S.get value) on_change=(S.set set_value)> <Label>"Search"</Label> <Search_field.Group> <Search_field.Search_icon /> <Search_field.Input class_="w-[280px]" placeholder="Search..." /> <Search_field.Clear_button /> </Search_field.Group> <Description> "Use keyboard shortcut to quickly focus this field" </Description> </Search_field> </div> <div class_="text-default-500 flex items-center gap-2 text-sm"> <span>"Press"</span> <Kbd><Kbd.Abbr key_value=`shift /> <Kbd.Content>"S"</Kbd.Content></Kbd> <span>"to focus the search field"</span> </div> </div>Render Function
Section titled “Render Function”HeroUI’s Render Function example gives the field 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 Search_field = Solidtype_heroui.Search_field
let make () = <Search_field class_="w-full max-w-64" name="docs" variant=`secondary> <Label class_="font-medium text-foreground">"Search docs"</Label> <Search_field.Group class_="rounded-xl bg-default"> <Search_field.Search_icon class_="text-muted" /> <Search_field.Input class_="placeholder:text-muted" placeholder="Components, guides..." /> <Search_field.Clear_button class_="text-muted" /> </Search_field.Group> </Search_field>Styling Reference
Section titled “Styling Reference”CSS Classes
Section titled “CSS Classes”.search-field, and.search-field--primary,.search-field--secondary,.search-field--full-width.search-field__group,.search-field__search-icon,.search-field__input,.search-field__clear-button
Interactive States
Section titled “Interactive States”- Empty:
[data-empty="true"], which hides the clear button - Hover, Focus within, Focus visible: on the group
- Disabled:
[data-disabled="true"] - Invalid:
[data-invalid="true"]
API Reference
Section titled “API Reference”Each prop beside the name HeroUI’s React component gives it.
SearchField
Section titled “SearchField”| React | solidtype | Type | Default | Description |
|---|---|---|---|---|
variant |
variant |
[ `primary | `secondary ] |
`primary |
Its look |
fullWidth |
full_width |
bool |
false |
Whether it takes its container’s width |
value |
value |
string |
Its query, controlled | |
defaultValue |
default_value |
string |
"" |
Its query at first, kept by itself |
onChange |
on_change |
string -> unit |
Told each change of its query | |
onSubmit |
on_submit |
string -> unit |
Told its query as Enter submits it | |
onClear |
on_clear |
unit -> unit |
Told as it is cleared | |
isDisabled |
is_disabled |
bool |
Whether it is disabled, else as its fieldset is | |
isInvalid |
is_invalid |
bool |
false |
Whether it is invalid |
isReadOnly |
is_read_only |
bool |
false |
Whether its query is kept |
isRequired |
is_required |
bool |
false |
Whether it is required |
name |
name |
string |
Its name in a form | |
aria-label |
aria_label |
string |
Its name where no label names it | |
className |
class_ |
string |
Added after HeroUI’s classes | |
onBlur |
on_blur |
Dom.focusEvent -> unit |
Called once focus leaves it for an element outside it |
SearchField.Group, SearchIcon, Input, ClearButton
Section titled “SearchField.Group, SearchIcon, Input, ClearButton”Each takes class_, added after HeroUI’s class; the input a placeholder;
the icon children, drawn in place of HeroUI’s magnifier.
Beside React
Section titled “Beside React”Original HeroUI documentation: SearchField.
The same HeroUI SearchField twice, under the same props: in solidtype on the left, in React on the right. Below them, every attribute of the two groups: a marked row is one they disagree on.
| attribute | solidtype | React |
|---|
