Components/Button Group

Button Group

Buttons joined into one control. Three published components, nine variants, and the one place in the kit where a component paints over its own children.

Button Group · Components frameLive in the browser · drawn to match the file
Orientation
Variant
ButtonButtonButtonButtonButton
Orientation=Horizontal · Variant=Outline352 × 32 in the file
How the join is made

Two ways to draw one hairline

Only the first and last button in a group keep their corners; everything between is square. What happens at the seam depends on whether the buttons have edges of their own.

Default and Secondary

Filled buttons have no edges, so the group inserts a 1px separator between them, in flow. Six buttons plus five separators is why the horizontal group measures 357 and not 352.

ButtonButtonButton
Outline

Two bordered buttons side by side give a 2px line at the seam. The fix in the file: strip the border off every button, put one border on the group, and lay a 1px hairline over each internal seam. Every line is then exactly 1px.

ButtonButtonButton
The examples frame

Eleven of these, doing real work

The second frame on the page is not a matrix. It is toolbars, split buttons and composers, with the captions below copied from it - because the point of a button group is what you build out of it, not the six variants on their own.

Mail toolbar - three groups separated by a gap
ArchiveReport
Snooze
Split button - primary action with an attached menu
Follow
Mute conversation
Mark as read
Report spam
Remove from list
Share conversation
Duplicate
Delete conversation
Split button with a popover - a compound action
Copilot
Start a new task with Copilot
Describe what needs to change in plain language.
I need to…
Copilot will open a pull request for review.
Composer - Placement: Start (leading action, then the field)
Send a message
Search - Placement: End (field, then the trailing action)
Search…
Invite link - Placement: Both (an action at each end)
acme.dev/invite/8f2a
Vertical - a stepper, stacked instead of side by side
Vertical - an icon rail on the default variant
Small size - history controls at 28px
UndoRedo
Secondary - document actions
CopyShareExport
Default - the primary group, split into action and menu
Publish
the one that gives the pattern away

The mail toolbar is three separate groups with a gap between them, not one group of five. Joining buttons says they belong together; the gap says Back is a different kind of action from Archive. A single group of five would have read as one control and lost that.

In the file

Three components, nine variants

Read straight out of the Penpot file. The axes below are the property names you will see in the variant dropdown.

Button GroupOrientation × VariantHorizontal · Vertical × Default · Outline · Secondary6
Button Group + InputPlacementStart · End · Both3
Button Group Popover Contentnonestandalone, no variants1

Using the Button Group

Because two bordered buttons side by side make a 2px line where they meet. The group strips the border off every button, carries one border itself, and lays a 1px hairline over each internal seam. Filled variants have no such problem, so they simply insert a 1px separator between buttons - which is why the horizontal group measures 357 there and 352 in Outline.

Only the first and the last. Everything between is square on all four corners, so the group reads as one control rather than a row of separate buttons. Vertical works the same way, top and bottom instead of left and right.

Because a search field with a button attached is a thing people build over and over, and doing it by hand means getting the seam right every time. Placement gives you the button at the start, the end, or both, and the input absorbs the width difference so the control stays the same size.

The panel that drops out of the icon button at the end of a group. It is published on its own, without variants, because the popover shell is already a component elsewhere in the kit - this is only the body that goes inside it.

Forms · 9 variants