Skip to content

ButtonGroup

<caos-button-group>

a run of buttons joined into one control

May be placed on a record page, an app’s home page, a page inside an app, an action on a record and a seam in the workspace frame.

Name Attribute Description Type Default Required
size size, markup only Control height from the platform size scale — sm, md or lg. Every button in the group is drawn at this height, whatever each one says for itself: a run of buttons at two different heights joined along one edge is a drawing mistake, not a layout. text — one of sm, md, lg md Optional
label label, markup only What the run of buttons is, for a screen reader — “Text style”, “Alignment”. Without it the group is announced as an unnamed group of controls. text none declared Optional
block block, markup only Fill the width of whatever holds it, with the buttons sharing that width evenly rather than the longest label taking it. boolean false Optional

This piece raises no events.

Name What goes in it
the default slot The buttons, in the order they are joined. Each keeps its own variant, its own pressed state and its own action; only the height is the group’s decision.
Design token What it controls
--caos-radius The corner radius of the two ends of the run. The corners between neighbours are squared.
--caos-button-radius-start Set by the group on every button but the first, to square the corners it shares with the one before it. Not an input an author sets here.
--caos-button-radius-end Set by the group on every button but the last, for the same reason at the other end.

Nothing else drives this piece by calling it.

Nothing on this piece can be read back.

Part Which piece of it When it is there
::part(group) the run itself Always

Several actions that belong to one another closely enough to read as one control: text styles, alignment, a view switcher, a run of toggles over the same thing. If the actions merely happen to sit near each other, they are a row of buttons and not a group.

  • ActionBar — A surface has several actions that are separate things, one of them primary, and the spare ones should collapse behind an overflow when it gets narrow.
  • SegmentedFilter — The run changes what is SHOWN rather than doing something, and exactly one of them is always in force.
  • OverflowMenu — The actions are secondary and belong behind a single trigger.

The run is a named group, from label. It is deliberately NOT a toolbar: a toolbar promises arrow-key navigation between its controls, and these are ordinary buttons that Tab moves through one at a time — announcing otherwise would teach a keyboard user a key that does nothing. Whichever button is under the pointer or holding focus is drawn in front of its neighbours, so a focus ring is never clipped by the button beside it. An icon-only button in a group still needs its own label, exactly as it does anywhere else.

Three actions over the same thing, read as one control rather than three.

{
"id": "example",
"section": "A joined run of actions",
"columns": 1,
"items": [
{
"id": "button_group_1",
"type": "component",
"key": "button_group",
"inputs": {
"label": "Record actions"
},
"children": [
{
"id": "button_2",
"type": "component",
"key": "button",
"inputs": {
"variant": "secondary"
},
"children": [
"Edit"
]
},
{
"id": "button_3",
"type": "component",
"key": "button",
"inputs": {
"variant": "secondary"
},
"children": [
"Clone"
]
},
{
"id": "button_4",
"type": "component",
"key": "button",
"inputs": {
"variant": "secondary"
},
"children": [
"Share"
]
}
]
}
]
}
<caos-button-group label="Record actions">
<caos-button variant="secondary">Edit</caos-button>
<caos-button variant="secondary">Clone</caos-button>
<caos-button variant="secondary">Share</caos-button>
</caos-button-group>

Each button carries its own pressed state, so several can be on at once. Exclusivity is not something the group imposes — a run where exactly one is always in force is a segmented filter.

{
"id": "example",
"section": "A run of toggles",
"columns": 1,
"items": [
{
"id": "button_group_1",
"type": "component",
"key": "button_group",
"inputs": {
"label": "Text style"
},
"children": [
{
"id": "button_2",
"type": "component",
"key": "button",
"inputs": {
"icon": "bold",
"label": "Bold",
"pressed": "true"
}
},
{
"id": "button_3",
"type": "component",
"key": "button",
"inputs": {
"icon": "italic",
"label": "Italic",
"pressed": "false"
}
},
{
"id": "button_4",
"type": "component",
"key": "button",
"inputs": {
"icon": "underline",
"label": "Underline",
"pressed": "false"
}
}
]
}
]
}
<caos-button-group label="Text style">
<caos-button icon="bold" label="Bold" pressed="true"></caos-button>
<caos-button icon="italic" label="Italic" pressed="false"></caos-button>
<caos-button icon="underline" label="Underline" pressed="false"></caos-button>
</caos-button-group>

The group’s size, not each button’s. The middle button asks for a large one and is drawn at the group’s height anyway, which is what stops a run from arriving misaligned.

{
"id": "example",
"section": "One height for the run",
"columns": 1,
"items": [
{
"id": "button_group_1",
"type": "component",
"key": "button_group",
"inputs": {
"size": "sm",
"label": "View"
},
"children": [
{
"id": "button_2",
"type": "component",
"key": "button",
"inputs": {
"variant": "secondary"
},
"children": [
"List"
]
},
{
"id": "button_3",
"type": "component",
"key": "button",
"inputs": {
"variant": "secondary",
"size": "lg"
},
"children": [
"Board"
]
},
{
"id": "button_4",
"type": "component",
"key": "button",
"inputs": {
"variant": "secondary"
},
"children": [
"Calendar"
]
}
]
}
]
}
<caos-button-group size="sm" label="View">
<caos-button variant="secondary">List</caos-button>
<caos-button variant="secondary" size="lg">Board</caos-button>
<caos-button variant="secondary">Calendar</caos-button>
</caos-button-group>