Skip to content

Button

A clickable button, HeroUI's on Kobalte's.

Solidtype_heroui.Button is Kobalte’s Button.Root, a native <button>, with the classes HeroUI’s own buttonVariants gives and the state its styles read, declared as React Aria writes it.

button_usage.mlx
module Button = Solidtype_heroui.Button
let make () = <Button on_click=(fun _ -> ())>"My Button"</Button>
button_variants.mlx
module Button = Solidtype_heroui.Button
let make () =
<div class_="flex flex-wrap items-center gap-3">
<Button>"Primary"</Button>
<Button variant=`secondary>"Secondary"</Button>
<Button variant=`tertiary>"Tertiary"</Button>
<Button variant=`outline>"Outline"</Button>
<Button variant=`ghost>"Ghost"</Button>
<Button variant=`danger>"Danger"</Button>
<Button variant=`danger_soft>"Danger soft"</Button>
</div>
button_sizes.mlx
module Button = Solidtype_heroui.Button
let make () =
<div class_="flex flex-wrap items-center gap-3">
<Button size=`sm>"Small"</Button>
<Button size=`md>"Medium"</Button>
<Button size=`lg>"Large"</Button>
</div>
button_icons.mlx
module Button = Solidtype_heroui.Button
let make () =
<div class_="flex flex-wrap items-center gap-3">
<Button><Icons.Plus /> "New file"</Button>
<Button variant=`secondary><Icons.Check /> "Approve"</Button>
<Button variant=`danger><Icons.Trash /> "Delete"</Button>
</div>

An icon-only button is named by its aria_label, as in React.

button_icon_only.mlx
module Button = Solidtype_heroui.Button
let make () =
<div class_="flex flex-wrap items-center gap-3">
<Button is_icon_only=true aria_label="New file"><Icons.Plus /></Button>
<Button is_icon_only=true aria_label="Approve" variant=`secondary>
<Icons.Check />
</Button>
<Button is_icon_only=true aria_label="Delete" variant=`danger>
<Icons.Trash />
</Button>
</div>
button_full_width.mlx
module Button = Solidtype_heroui.Button
let make () =
<div class_="flex w-72 flex-col gap-3">
<Button full_width=true>"Full width"</Button>
<Button full_width=true variant=`secondary>"Full width"</Button>
</div>
button_disabled.mlx
module Button = Solidtype_heroui.Button
let make () =
<div class_="flex flex-wrap items-center gap-3">
<Button is_disabled=true>"Primary"</Button>
<Button is_disabled=true variant=`secondary>"Secondary"</Button>
<Button is_disabled=true variant=`danger>"Danger"</Button>
</div>

HeroUI’s Loading, Social Buttons, Render Function and custom variants examples need what the port does not take yet: isPending, render props and render.

class_ is added after HeroUI’s classes.

button_tailwind.mlx
module Button = Solidtype_heroui.Button
let make () =
<Button class_="bg-purple-500 text-white hover:bg-purple-600">
"Custom button"
</Button>

HeroUI’s classes are global, so a stylesheet restyles every button, as with HeroUI in React:

@layer components {
.button {
@apply font-semibold uppercase;
}
.button--primary {
@apply bg-indigo-600 hover:bg-indigo-700;
}
}

The classes HeroUI’s button styles define, which variant, size, full_width and is_icon_only choose:

  • .button, and its sizes .button--sm, .button--md, .button--lg
  • .button--primary, .button--secondary, .button--tertiary, .button--outline, .button--ghost, .button--danger, .button--danger-soft
  • .button--icon-only, .button--full-width

HeroUI’s styles read a pseudo-class or a data attribute for each; the port declares each attribute as React Aria writes it:

  • Hover: :hover or [data-hovered="true"]
  • Pressed: :active or [data-pressed="true"]
  • Focus: :focus-visible or [data-focus-visible="true"]
  • Disabled: :disabled or [data-disabled="true"]

Kobalte writes only data-disabled, and empty, so the port keeps the rest itself, by Solidtype_heroui.Interaction, as React Aria does: hovered by a mouse but never a touch, pressed by a pointer or by Enter and Space, focus-visible only after a key. Its test puts the port and the same Button in React through the same steps and compares what each shows after every one.

Each prop beside the name HeroUI’s React component gives it. A tag is the string React takes, a hyphen written as an underscore: `danger_soft is "danger-soft".

React solidtype Type Default Description
variant variant [ `primary | `secondary | `tertiary | `outline | `ghost | `danger | `danger_soft ] `primary Visual style
size size [ `sm | `md | `lg ] `md Size
fullWidth full_width bool false Whether it takes its container’s width
isIconOnly is_icon_only bool false Whether it holds an icon alone
isDisabled is_disabled bool false Whether it is disabled
slot slot [ `trigger ] Makes it the trigger of the part above it, a Disclosure.Heading’s
type type_ [ `button | `submit | `reset | `menu ] `button The button’s type in a form
aria-label aria_label string Its name where it shows an icon alone
onPress on_click Dom.mouseEvent -> unit Kobalte’s click, by mouse, touch or keyboard, where React Aria’s is a press
className class_ string Added after HeroUI’s classes
children children elements Its content
isPending — Not yet
render props — Not yet

Original HeroUI documentation: Button.

The same HeroUI Button twice, under the same props: in solidtype on the left, in React on the right. Below them, every attribute of the two elements: a marked row is one they disagree on, and a dimmed row is a framework’s own – Solid’s hydration key, React Aria’s markers and the id it generates – which no style reads. Hover, focus and press them to see the state each sets.

Button

solidtype — OCaml, on Solid and Kobalte
React — TypeScript, on React Aria
attributesolidtypeReact