Skip to content

ButtonGroup

Related buttons, grouped with one look.

Solidtype_heroui.Button_group is a <div role="group"> of Solidtype_heroui.Buttons, with the classes HeroUI’s own buttonGroupVariants gives. Kobalte has no group, and a group has no behaviour: it gives the buttons inside it its variant, size, is_disabled and full_width, each where a button sets none itself.

HeroUI’s examples, with HeroUI’s icons from @gravity-ui/icons. A split button’s chevron opens a Dropdown in HeroUI’s, which comes with Dropdown’s port; here it is the button alone.

button_group_usage.mlx
module Button = Solidtype_heroui.Button
module Button_group = Solidtype_heroui.Button_group
module Chip = Solidtype_heroui.Chip
(* HeroUI's split button opens a Dropdown, which comes with its port; here
its chevron is the button alone. *)
let make () =
<div class_="flex flex-col items-start gap-6">
<div class_="flex flex-col gap-2">
<Button_group>
<Button>"Merge pull request"</Button>
<Button is_icon_only=true aria_label="More options">
<Button_group.Separator /> <Gravity.Chevron_down />
</Button>
</Button_group>
</div>
<div class_="flex flex-col gap-2">
<div class_="flex flex-wrap gap-x-2 gap-y-4">
<Button_group variant=`tertiary>
<Button>
<Gravity.Code_fork class_="size-3.5" />
"Fork"
<Chip color=`accent size=`sm variant=`soft>"24"</Chip>
</Button>
<Button is_icon_only=true aria_label="More fork options">
<Button_group.Separator /> <Gravity.Chevron_down />
</Button>
</Button_group>
<Button_group variant=`tertiary>
<Button is_icon_only=true aria_label="Show QR code">
<Gravity.Qr_code />
</Button>
<Button><Button_group.Separator /> "Scan to pay"</Button>
</Button_group>
<Button_group variant=`tertiary>
<Button>
<Gravity.Thumbs_up />
<span class_="text-xs font-semibold">"2.4K"</span>
</Button>
<Button is_icon_only=true aria_label="Dislike">
<Button_group.Separator /> <Gravity.Thumbs_down />
</Button>
</Button_group>
<Button_group variant=`tertiary>
<Button><Gravity.Star class_="size-3.5" /> "Star"</Button>
<Button class_="px-2">
<Button_group.Separator />
<Chip color=`accent size=`sm variant=`soft>"104"</Chip>
</Button>
</Button_group>
<Button_group variant=`tertiary>
<Button><Gravity.Pin /> "Pinned"</Button>
<Button is_icon_only=true aria_label="More pin options">
<Button_group.Separator /> <Gravity.Chevron_down />
</Button>
</Button_group>
</div>
</div>
<div class_="flex flex-col gap-2">
<Button_group variant=`tertiary>
<Button><Gravity.Chevron_left /> "Previous"</Button>
<Button>
<Button_group.Separator /> "Next" <Gravity.Chevron_right />
</Button>
</Button_group>
</div>
<div class_="flex flex-col gap-2">
<Button_group variant=`tertiary>
<Button><Gravity.Picture /> "Photos"</Button>
<Button><Button_group.Separator /> <Gravity.Video /> "Videos"</Button>
<Button is_icon_only=true aria_label="More options">
<Button_group.Separator /> <Gravity.Ellipsis />
</Button>
</Button_group>
</div>
<div class_="flex flex-col gap-2">
<Button_group variant=`tertiary>
<Button>"Left"</Button>
<Button><Button_group.Separator /> "Center"</Button>
<Button><Button_group.Separator /> "Right"</Button>
</Button_group>
</div>
<div class_="flex flex-col gap-2">
<Button_group variant=`tertiary>
<Button is_icon_only=true aria_label="Align left">
<Gravity.Text_align_left />
</Button>
<Button is_icon_only=true aria_label="Align center">
<Button_group.Separator /> <Gravity.Text_align_center />
</Button>
<Button is_icon_only=true aria_label="Align right">
<Button_group.Separator /> <Gravity.Text_align_right />
</Button>
<Button is_icon_only=true aria_label="Justify">
<Button_group.Separator /> <Gravity.Text_align_justify />
</Button>
</Button_group>
</div>
</div>

Primary

Secondary

Tertiary

Outline

Ghost

Danger

button_group_variants.mlx
module Button = Solidtype_heroui.Button
module Button_group = Solidtype_heroui.Button_group
let group ~label ~variant =
<div class_="flex flex-col gap-2">
<p class_="text-sm text-muted">(fun () -> Solidtype.Jsx.string label)</p>
<Button_group variant=(fun () -> variant)>
<Button>"First"</Button>
<Button><Button_group.Separator /> "Second"</Button>
<Button><Button_group.Separator /> "Third"</Button>
</Button_group>
</div>
let make () =
<div class_="flex flex-col gap-6">
(fun () -> Solidtype.Jsx.element (group ~label:"Primary" ~variant:`primary))
(fun () ->
Solidtype.Jsx.element (group ~label:"Secondary" ~variant:`secondary))
(fun () ->
Solidtype.Jsx.element (group ~label:"Tertiary" ~variant:`tertiary))
(fun () -> Solidtype.Jsx.element (group ~label:"Outline" ~variant:`outline))
(fun () -> Solidtype.Jsx.element (group ~label:"Ghost" ~variant:`ghost))
(fun () -> Solidtype.Jsx.element (group ~label:"Danger" ~variant:`danger))
</div>

Small

Medium (default)

Large

button_group_sizes.mlx
module Button = Solidtype_heroui.Button
module Button_group = Solidtype_heroui.Button_group
let group ~label ~size =
<div class_="flex flex-col items-start gap-2">
<p class_="text-sm text-muted">(fun () -> Solidtype.Jsx.string label)</p>
<Button_group size=(fun () -> size) variant=`secondary>
<Button>"First"</Button>
<Button><Button_group.Separator /> "Second"</Button>
<Button><Button_group.Separator /> "Third"</Button>
</Button_group>
</div>
let make () =
<div class_="flex flex-col gap-4">
(fun () -> Solidtype.Jsx.element (group ~label:"Small" ~size:`sm))
(fun () ->
Solidtype.Jsx.element (group ~label:"Medium (default)" ~size:`md))
(fun () -> Solidtype.Jsx.element (group ~label:"Large" ~size:`lg))
</div>

orientation arranges the buttons horizontally or vertically.

Horizontal
Vertical
button_group_orientation.mlx
module Button = Solidtype_heroui.Button
module Button_group = Solidtype_heroui.Button_group
let group ~label ~orientation =
<div class_="flex flex-col gap-2">
<span class_="text-sm text-muted">
(fun () -> Solidtype.Jsx.string label)
</span>
<Button_group orientation=(fun () -> orientation) variant=`tertiary>
<Button is_icon_only=true aria_label="Align left">
<Gravity.Text_align_left />
</Button>
<Button is_icon_only=true aria_label="Align center">
<Button_group.Separator /> <Gravity.Text_align_center />
</Button>
<Button is_icon_only=true aria_label="Align right">
<Button_group.Separator /> <Gravity.Text_align_right />
</Button>
<Button is_icon_only=true aria_label="Justify">
<Button_group.Separator /> <Gravity.Text_align_justify />
</Button>
</Button_group>
</div>
let make () =
<div class_="flex items-start gap-8">
(fun () ->
Solidtype.Jsx.element (group ~label:"Horizontal" ~orientation:`horizontal))
(fun () ->
Solidtype.Jsx.element (group ~label:"Vertical" ~orientation:`vertical))
</div>

With icons

Icon only buttons

button_group_icons.mlx
module Button = Solidtype_heroui.Button
module Button_group = Solidtype_heroui.Button_group
let make () =
<div class_="flex flex-col gap-6">
<div class_="flex flex-col items-start gap-2">
<p class_="text-sm text-muted">"With icons"</p>
<Button_group variant=`secondary>
<Button><Gravity.Globe /> "Search"</Button>
<Button><Button_group.Separator /> <Gravity.Plus /> "Add"</Button>
<Button>
<Button_group.Separator /> <Gravity.Trash_bin /> "Delete"
</Button>
</Button_group>
</div>
<div class_="flex flex-col items-start gap-2">
<p class_="text-sm text-muted">"Icon only buttons"</p>
<Button_group variant=`tertiary>
<Button is_icon_only=true aria_label="Search"><Gravity.Globe /></Button>
<Button is_icon_only=true aria_label="Add">
<Button_group.Separator /> <Gravity.Plus />
</Button>
<Button is_icon_only=true aria_label="Delete">
<Button_group.Separator /> <Gravity.Trash_bin />
</Button>
</Button_group>
</div>
</div>
button_group_full_width.mlx
module Button = Solidtype_heroui.Button
module Button_group = Solidtype_heroui.Button_group
let make () =
<div class_="w-[400px] space-y-3">
<Button_group full_width=true>
<Button>"First"</Button>
<Button><Button_group.Separator /> "Second"</Button>
<Button><Button_group.Separator /> "Third"</Button>
</Button_group>
<Button_group full_width=true>
<Button is_icon_only=true aria_label="Align left">
<Gravity.Text_align_left />
</Button>
<Button is_icon_only=true aria_label="Align center">
<Button_group.Separator /> <Gravity.Text_align_center />
</Button>
<Button is_icon_only=true aria_label="Align right">
<Button_group.Separator /> <Gravity.Text_align_right />
</Button>
</Button_group>
</div>

A button’s own is_disabled overrides its group’s.

All buttons disabled

Group disabled, but one button overrides

button_group_disabled.mlx
module Button = Solidtype_heroui.Button
module Button_group = Solidtype_heroui.Button_group
let make () =
<div class_="flex flex-col gap-6">
<div class_="flex flex-col items-start gap-2">
<p class_="text-sm text-muted">"All buttons disabled"</p>
<Button_group is_disabled=true>
<Button>"First"</Button>
<Button><Button_group.Separator /> "Second"</Button>
<Button><Button_group.Separator /> "Third"</Button>
</Button_group>
</div>
<div class_="flex flex-col items-start gap-2">
<p class_="text-sm text-muted">
"Group disabled, but one button overrides"
</p>
<Button_group is_disabled=true>
<Button>"First"</Button>
<Button><Button_group.Separator /> "Second"</Button>
<Button is_disabled=false>
<Button_group.Separator /> "Third (enabled)"
</Button>
</Button_group>
</div>
</div>

A button without a Button_group.Separator draws no line before it.

button_group_without_separator.mlx
module Button = Solidtype_heroui.Button
module Button_group = Solidtype_heroui.Button_group
let make () =
<Button_group>
<Button>"First"</Button> <Button>"Second"</Button> <Button>"Third"</Button>
</Button_group>

class_ is added after HeroUI’s classes, on the group and on each button.

button_group_tailwind.mlx
module Button = Solidtype_heroui.Button
module Button_group = Solidtype_heroui.Button_group
(* HeroUI's split button opens a Dropdown, which comes with its port; here
its chevron is the button alone. *)
let make () =
<Button_group>
<Button class_="rounded-none bg-[#08872B] data-hovered:bg-[#0FBF3E]">
"Merge pull request"
</Button>
<Button
is_icon_only=true
aria_label="Merge options"
class_="rounded-none bg-[#08872B] data-hovered:bg-[#0FBF3E]">
<Button_group.Separator /> <Gravity.Chevron_down class_="size-4" />
</Button>
</Button_group>

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

@layer components {
.button-group {
@apply gap-2 rounded-lg;
}
.button-group__separator {
@apply opacity-25;
}
}
  • .button-group, and its orientations .button-group--horizontal, .button-group--vertical
  • .button-group--full-width
  • .button-group__separator

HeroUI’s styles round the first button’s start edge and the last’s end edge, and no edge between, and take away a pressed button’s scale.

  • Disabled: [data-disabled="true"] on the group, while it is disabled

Each button shows its own state, as Solidtype_heroui.Button does.

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

React solidtype Type Default Description
variant variant [ `primary | `secondary | `tertiary | `outline | `ghost | `danger | `danger_soft ] The variant of each button that sets none
size size [ `sm | `md | `lg ] The size of each button that sets none
orientation orientation [ `horizontal | `vertical ] `horizontal How the buttons are arranged
fullWidth full_width bool false Whether it takes its container’s width
isDisabled is_disabled bool false Whether each button that sets none is disabled
className class_ string Added after HeroUI’s classes
children children elements Its buttons
React solidtype Type Description
className class_ string Added after HeroUI’s class

Original HeroUI documentation: ButtonGroup.

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

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