Skip to content

InputGroup

An input with what goes before and after it.

Solidtype_heroui.Input_group is an input or a text area with its prefix and suffix, in a group with the classes HeroUI’s own inputGroupVariants gives. A click on the group but on its input gives an input the focus, as HeroUI’s does, though not a text area. Inside a TextField its input is the field’s, which the field’s label names, and the group takes the field’s variant where it sets none. Kobalte has no group.

HeroUI’s examples, with HeroUI’s icons from @gravity-ui/icons.

input_group_usage.mlx
module Description = Solidtype_heroui.Description
module Input_group = Solidtype_heroui.Input_group
module Label = Solidtype_heroui.Label
module Text_field = Solidtype_heroui.Text_field
let make () =
<Text_field class_="w-full max-w-[280px]" name="email">
<Label>"Email address"</Label>
<Input_group>
<Input_group.Prefix>
<Gravity.Envelope class_="size-4 text-muted" />
</Input_group.Prefix>
<Input_group.Input
class_="w-full max-w-[280px]" placeholder="name@email.com"
/>
</Input_group>
</Text_field>
<Input_group>
<Input_group.Prefix>"https://"</Input_group.Prefix>
<Input_group.Input />
<Input_group.Suffix>".com"</Input_group.Suffix>
</Input_group>
input_group_variants.mlx
module Description = Solidtype_heroui.Description
module Input_group = Solidtype_heroui.Input_group
module Label = Solidtype_heroui.Label
module Text_field = Solidtype_heroui.Text_field
let make () =
<div class_="flex flex-col gap-4">
<Text_field class_="w-[280px]" name="primary">
<Label>"Primary variant"</Label>
<Input_group variant=`primary>
<Input_group.Prefix>
<Gravity.Envelope class_="size-4 text-muted" />
</Input_group.Prefix>
<Input_group.Input placeholder="name@email.com" />
</Input_group>
</Text_field>
<Text_field class_="w-[280px]" name="secondary">
<Label>"Secondary variant"</Label>
<Input_group variant=`secondary>
<Input_group.Prefix>
<Gravity.Envelope class_="size-4 text-muted" />
</Input_group.Prefix>
<Input_group.Input placeholder="name@email.com" />
</Input_group>
</Text_field>
</div>
We'll never share this with anyone else
input_group_surface.mlx
module Description = Solidtype_heroui.Description
module Input_group = Solidtype_heroui.Input_group
module Label = Solidtype_heroui.Label
module Text_field = Solidtype_heroui.Text_field
module Surface = Solidtype_heroui.Surface
let make () =
<Surface class_="rounded-2xl p-6">
<Text_field class_="w-full max-w-[280px]" name="email">
<Label>"Email address"</Label>
<Input_group variant=`secondary>
<Input_group.Prefix>
<Gravity.Envelope class_="size-4 text-muted" />
</Input_group.Prefix>
<Input_group.Input
class_="w-full max-w-[280px]" placeholder="name@email.com"
/>
</Input_group>
<Description>"We'll never share this with anyone else"</Description>
</Text_field>
</Surface>
input_group_loading.mlx
module Description = Solidtype_heroui.Description
module Input_group = Solidtype_heroui.Input_group
module Label = Solidtype_heroui.Label
module Text_field = Solidtype_heroui.Text_field
module Spinner = Solidtype_heroui.Spinner
let make () =
<Text_field
class_="w-full max-w-[280px]" default_value="Sending..." name="status">
<Input_group>
<Input_group.Input class_="w-full max-w-[280px]" />
<Input_group.Suffix><Spinner class_="size-4" /></Input_group.Suffix>
</Input_group>
</Text_field>
What customers would pay
input_group_required.mlx
module Description = Solidtype_heroui.Description
module Input_group = Solidtype_heroui.Input_group
module Label = Solidtype_heroui.Label
module Text_field = Solidtype_heroui.Text_field
let make () =
<div class_="flex flex-col gap-4">
<Text_field is_required=true class_="w-full max-w-[280px]" name="email">
<Label>"Email address"</Label>
<Input_group>
<Input_group.Prefix>
<Gravity.Envelope class_="size-4 text-muted" />
</Input_group.Prefix>
<Input_group.Input
class_="w-full max-w-[280px]" placeholder="name@email.com"
/>
</Input_group>
</Text_field>
<Text_field is_required=true class_="w-full max-w-[280px]" name="price">
<Label>"Set a price"</Label>
<Input_group>
<Input_group.Prefix>"$"</Input_group.Prefix>
<Input_group.Input
class_="w-full max-w-[200px]" placeholder="0" type_="number"
/>
<Input_group.Suffix>"USD"</Input_group.Suffix>
</Input_group>
<Description>"What customers would pay"</Description>
</Text_field>
</div>
input_group_disabled.mlx
module Description = Solidtype_heroui.Description
module Input_group = Solidtype_heroui.Input_group
module Label = Solidtype_heroui.Label
module Text_field = Solidtype_heroui.Text_field
let make () =
<div class_="flex flex-col gap-4">
<Text_field
is_disabled=true
class_="w-full max-w-[280px]"
default_value="name@email.com"
name="email">
<Label>"Email address"</Label>
<Input_group>
<Input_group.Prefix>
<Gravity.Envelope class_="size-4 text-muted" />
</Input_group.Prefix>
<Input_group.Input class_="w-full max-w-[280px]" />
</Input_group>
</Text_field>
<Text_field
is_disabled=true
class_="w-full max-w-[280px]"
default_value="10"
name="price">
<Label>"Set a price"</Label>
<Input_group>
<Input_group.Prefix>"$"</Input_group.Prefix>
<Input_group.Input class_="w-full max-w-[200px]" type_="number" />
<Input_group.Suffix>"USD"</Input_group.Suffix>
</Input_group>
</Text_field>
</div>
input_group_full_width.mlx
module Description = Solidtype_heroui.Description
module Input_group = Solidtype_heroui.Input_group
module Label = Solidtype_heroui.Label
module Text_field = Solidtype_heroui.Text_field
let make () =
<div class_="w-[400px] space-y-4">
<Text_field full_width=true name="email">
<Label>"Email address"</Label>
<Input_group full_width=true>
<Input_group.Prefix>
<Gravity.Envelope class_="size-4 text-muted" />
</Input_group.Prefix>
<Input_group.Input placeholder="name@email.com" />
</Input_group>
</Text_field>
<Text_field full_width=true name="password">
<Label>"Password"</Label>
<Input_group full_width=true>
<Input_group.Input placeholder="Enter password" type_="password" />
<Input_group.Suffix>
<Gravity.Eye class_="size-4 text-muted" />
</Input_group.Suffix>
</Input_group>
</Text_field>
</div>
input_group_text_prefix.mlx
module Description = Solidtype_heroui.Description
module Input_group = Solidtype_heroui.Input_group
module Label = Solidtype_heroui.Label
module Text_field = Solidtype_heroui.Text_field
let make () =
<Text_field
class_="w-full max-w-[280px]" default_value="heroui.com" name="website">
<Label>"Website"</Label>
<Input_group>
<Input_group.Prefix>"https://"</Input_group.Prefix>
<Input_group.Input class_="w-full max-w-[280px]" />
</Input_group>
</Text_field>
input_group_text_suffix.mlx
module Description = Solidtype_heroui.Description
module Input_group = Solidtype_heroui.Input_group
module Label = Solidtype_heroui.Label
module Text_field = Solidtype_heroui.Text_field
let make () =
<Text_field
class_="w-full max-w-[280px]" default_value="heroui" name="website">
<Label>"Website"</Label>
<Input_group>
<Input_group.Input class_="w-full max-w-[280px]" />
<Input_group.Suffix>".com"</Input_group.Suffix>
</Input_group>
</Text_field>
input_group_icon_prefix_text_suffix.mlx
module Description = Solidtype_heroui.Description
module Input_group = Solidtype_heroui.Input_group
module Label = Solidtype_heroui.Label
module Text_field = Solidtype_heroui.Text_field
let make () =
<Text_field
class_="w-full max-w-[280px]" default_value="heroui" name="website">
<Label>"Website"</Label>
<Input_group>
<Input_group.Prefix>
<Gravity.Globe class_="size-4 text-muted" />
</Input_group.Prefix>
<Input_group.Input class_="w-full max-w-[280px]" />
<Input_group.Suffix>".com"</Input_group.Suffix>
</Input_group>
</Text_field>
input_group_copy_suffix.mlx
module Description = Solidtype_heroui.Description
module Input_group = Solidtype_heroui.Input_group
module Label = Solidtype_heroui.Label
module Text_field = Solidtype_heroui.Text_field
module Button = Solidtype_heroui.Button
let make () =
<Text_field
class_="w-full max-w-[280px]" default_value="heroui.com" name="website">
<Label>"Website"</Label>
<Input_group>
<Input_group.Input class_="w-full max-w-[280px]" />
<Input_group.Suffix class_="pe-0">
<Button is_icon_only=true aria_label="Copy" size=`sm variant=`ghost>
<Gravity.Copy class_="size-4" />
</Button>
</Input_group.Suffix>
</Input_group>
</Text_field>
input_group_icon_prefix_copy_suffix.mlx
module Description = Solidtype_heroui.Description
module Input_group = Solidtype_heroui.Input_group
module Label = Solidtype_heroui.Label
module Text_field = Solidtype_heroui.Text_field
module Button = Solidtype_heroui.Button
let make () =
<Text_field
class_="w-full max-w-[280px]" default_value="heroui.com" name="website">
<Label>"Website"</Label>
<Input_group>
<Input_group.Prefix>
<Gravity.Globe class_="size-4 text-muted" />
</Input_group.Prefix>
<Input_group.Input class_="w-full max-w-[280px]" />
<Input_group.Suffix class_="pe-0">
<Button is_icon_only=true aria_label="Copy" size=`sm variant=`ghost>
<Gravity.Copy class_="size-4" />
</Button>
</Input_group.Suffix>
</Input_group>
</Text_field>
input_group_password.mlx
module Description = Solidtype_heroui.Description
module Input_group = Solidtype_heroui.Input_group
module Label = Solidtype_heroui.Label
module Text_field = Solidtype_heroui.Text_field
module S = Solidtype.Solid
module Button = Solidtype_heroui.Button
let make () =
let visible, set_visible = S.create_signal false in
<Text_field class_="w-full max-w-[280px]" name="password">
<Label>"Password"</Label>
<Input_group>
<Input_group.Input
class_="w-full max-w-[280px]"
type_=(fun () -> if S.get visible then "text" else "password")
value=(fun () ->
if S.get visible then "87$2h.3diua" else {js|••••••••|js})
/>
<Input_group.Suffix class_="pe-0">
<Button
is_icon_only=true
aria_label=(fun () ->
if S.get visible then "Hide password"
else "Show password")
size=`sm
variant=`ghost
on_click=(fun _ -> S.set set_visible (not (S.get visible)))>
(fun () ->
if S.get visible then
Solidtype.Jsx.element <Gravity.Eye class_="size-4" />
else Solidtype.Jsx.element <Gravity.Eye_slash class_="size-4" />)
</Button>
</Input_group.Suffix>
</Input_group>
</Text_field>
input_group_shortcut.mlx
module Description = Solidtype_heroui.Description
module Input_group = Solidtype_heroui.Input_group
module Label = Solidtype_heroui.Label
module Text_field = Solidtype_heroui.Text_field
module Kbd = Solidtype_heroui.Kbd
let make () =
<Text_field class_="w-full max-w-[280px]" name="command">
<Input_group>
<Input_group.Input
aria_label="Command" class_="w-full max-w-[280px]" placeholder="Command"
/>
<Input_group.Suffix class_="pe-2">
<Kbd>
<Kbd.Abbr key_value=`command /> <Kbd.Content>"K"</Kbd.Content>
</Kbd>
</Input_group.Suffix>
</Input_group>
</Text_field>
input_group_badge_suffix.mlx
module Description = Solidtype_heroui.Description
module Input_group = Solidtype_heroui.Input_group
module Label = Solidtype_heroui.Label
module Text_field = Solidtype_heroui.Text_field
module Chip = Solidtype_heroui.Chip
let make () =
<Text_field class_="w-full max-w-[280px]" name="email">
<Input_group>
<Input_group.Input
aria_label="Email address"
class_="w-full max-w-[280px]"
placeholder="Email address"
/>
<Input_group.Suffix class_="pe-2">
<Chip color=`accent size=`md variant=`soft>"Pro"</Chip>
</Input_group.Suffix>
</Input_group>
</Text_field>
Please enter a valid email address
Price must be greater than 0
input_group_invalid.mlx
module Description = Solidtype_heroui.Description
module Input_group = Solidtype_heroui.Input_group
module Label = Solidtype_heroui.Label
module Text_field = Solidtype_heroui.Text_field
module Field_error = Solidtype_heroui.Field_error
let make () =
<div class_="flex flex-col gap-4">
<Text_field
is_invalid=true
is_required=true
class_="w-full max-w-[280px]"
name="email">
<Label>"Email address"</Label>
<Input_group>
<Input_group.Prefix>
<Gravity.Envelope class_="size-4 text-muted" />
</Input_group.Prefix>
<Input_group.Input
class_="w-full max-w-[280px]" placeholder="name@email.com"
/>
</Input_group>
<Field_error>"Please enter a valid email address"</Field_error>
</Text_field>
<Text_field
is_invalid=true
is_required=true
class_="w-full max-w-[280px]"
name="price">
<Label>"Set a price"</Label>
<Input_group>
<Input_group.Prefix>"$"</Input_group.Prefix>
<Input_group.Input
class_="w-full max-w-[200px]" placeholder="0" type_="number"
/>
<Input_group.Suffix>"USD"</Input_group.Suffix>
</Input_group>
<Field_error>"Price must be greater than 0"</Field_error>
</Text_field>
</div>
We'll never share this with anyone else
input_group_prefix_icon.mlx
module Description = Solidtype_heroui.Description
module Input_group = Solidtype_heroui.Input_group
module Label = Solidtype_heroui.Label
module Text_field = Solidtype_heroui.Text_field
let make () =
<Text_field class_="w-full max-w-[280px]" name="email">
<Label>"Email address"</Label>
<Input_group>
<Input_group.Prefix>
<Gravity.Envelope class_="size-4 text-muted" />
</Input_group.Prefix>
<Input_group.Input
class_="w-full max-w-[280px]" placeholder="name@email.com"
/>
</Input_group>
<Description>"We'll never share this with anyone else"</Description>
</Text_field>
We don't send spam
input_group_suffix_icon.mlx
module Description = Solidtype_heroui.Description
module Input_group = Solidtype_heroui.Input_group
module Label = Solidtype_heroui.Label
module Text_field = Solidtype_heroui.Text_field
let make () =
<Text_field class_="w-full max-w-[280px]" name="email">
<Label>"Email address"</Label>
<Input_group>
<Input_group.Input
class_="w-full max-w-[280px]" placeholder="name@email.com"
/>
<Input_group.Suffix>
<Gravity.Envelope class_="size-4 text-muted" />
</Input_group.Suffix>
</Input_group>
<Description>"We don't send spam"</Description>
</Text_field>
What customers would pay
input_group_prefix_suffix.mlx
module Description = Solidtype_heroui.Description
module Input_group = Solidtype_heroui.Input_group
module Label = Solidtype_heroui.Label
module Text_field = Solidtype_heroui.Text_field
let make () =
<Text_field class_="w-full max-w-[280px]" default_value="10" name="price">
<Label>"Set a price"</Label>
<Input_group>
<Input_group.Prefix>"$"</Input_group.Prefix>
<Input_group.Input class_="w-full max-w-[200px]" type_="number" />
<Input_group.Suffix>"USD"</Input_group.Suffix>
</Input_group>
<Description>"What customers would pay"</Description>
</Text_field>

HeroUI’s buttons here show a Tooltip each, which comes with Tooltip’s port; the port’s TextField takes no aria_label yet, so the text area names itself, as the label HeroUI’s gives its input.

input_group_text_area.mlx
module Description = Solidtype_heroui.Description
module Input_group = Solidtype_heroui.Input_group
module Label = Solidtype_heroui.Label
module Text_field = Solidtype_heroui.Text_field
module S = Solidtype.Solid
module Button = Solidtype_heroui.Button
module Spinner = Solidtype_heroui.Spinner
let make () =
let value, set_value = S.create_signal "" in
let submitting, set_submitting = S.create_signal false in
let empty () = String.equal (String.trim (S.get value)) "" in
let submit _ =
if not (empty ()) then begin
S.set set_submitting true;
ignore
(Js.Global.setTimeout
~f:(fun () ->
S.set set_submitting false;
S.set set_value "")
1000
: Js.Global.timeoutId)
end
in
<Text_field
full_width=true
class_="flex w-sm flex-col sm:w-lg"
name="prompt"
value=(fun () -> S.get value)
on_change=(S.set set_value)>
<Input_group full_width=true class_="flex flex-col gap-2 rounded-3xl py-2">
<Input_group.Prefix class_="px-3 py-0">
<Button aria_label="Add context" size=`sm variant=`outline>
<Gravity.At /> "Add Context"
</Button>
</Input_group.Prefix>
<Input_group.Text_area
aria_label="Prompt input"
class_="w-full resize-none px-3.5 py-0"
placeholder="Assign tasks or ask anything..."
rows="5"
/>
<Input_group.Suffix class_="flex w-full items-center gap-1.5 px-3 py-0">
<Button
is_icon_only=true aria_label="Attach file" size=`sm variant=`tertiary>
<Gravity.Plus />
</Button>
<Button
is_icon_only=true aria_label="Connect Apps" size=`sm variant=`tertiary>
<Gravity.Plug_connection />
</Button>
<div class_="ms-auto flex items-center gap-1.5">
<Button
is_icon_only=true aria_label="Voice input" size=`sm variant=`ghost>
<Gravity.Microphone />
</Button>
<Button
is_icon_only=true
aria_label="Send prompt"
is_disabled=(fun () -> empty ())
on_click=submit>
(fun () ->
if S.get submitting then
Solidtype.Jsx.element <Spinner color=`current size=`sm />
else Solidtype.Jsx.element <Gravity.Arrow_up />)
</Button>
</div>
</Input_group.Suffix>
</Input_group>
</Text_field>

class_ is added after HeroUI’s classes.

input_group_tailwind.mlx
module Description = Solidtype_heroui.Description
module Input_group = Solidtype_heroui.Input_group
module Label = Solidtype_heroui.Label
module Text_field = Solidtype_heroui.Text_field
let make () =
<Text_field class_="w-full max-w-xs" name="email">
<Label>"Work email"</Label>
<Input_group
class_="rounded-xl border border-border/80 bg-default shadow-sm">
<Input_group.Prefix>
<Gravity.Envelope class_="size-4 text-muted" />
</Input_group.Prefix>
<Input_group.Input placeholder="you@company.com" />
</Input_group>
</Text_field>
  • .input-group, and .input-group--primary, .input-group--secondary, .input-group--full-width
  • .input-group__prefix, .input-group__input, .input-group__suffix
  • Hover: [data-hovered="true"]
  • Focus within: [data-focus-within="true"]
  • Focus visible: [data-focus-visible="true"]
  • Disabled: [data-disabled="true"]
  • Invalid: [data-invalid="true"]

Each prop beside the name HeroUI’s React component gives it.

React solidtype Type Default Description
variant variant [ `primary | `secondary ] its field’s, else `primary Its look
fullWidth full_width bool false Whether it takes its container’s width
isDisabled is_disabled bool its field’s Whether it is shown disabled
isInvalid is_invalid bool its field’s Whether it is shown invalid
className class_ string Added after HeroUI’s classes

Each takes every attribute its element takes, as Input and TextArea do.

Each takes class_, added after HeroUI’s class, and its children.

Original HeroUI documentation: InputGroup.

The same HeroUI InputGroup 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.

solidtype — OCaml, on Solid and Kobalte
https://
.com
React — TypeScript, on React Aria
attributesolidtypeReact