Skip to content

ButtonGroup

A row of buttons that belong together. The corners that face a neighbour are squared off, and the shared props are set once for the whole set.

tsx
import { Button, ButtonGroup } from 'neba';

<ButtonGroup variant="outline">
  <Button>Day</Button>
  <Button>Week</Button>
  <Button>Month</Button>
</ButtonGroup>;

Props

PropTypeDefaultDescription
variantshared'solid' | 'outline' | 'text'Applied to every button in the group. Unset means the Button's own default stands
sizeshared'xs' | 'sm' | 'md' | 'lg' | 'xl'Height and type scale for every button in the group
colorshared'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info'Colour role for every button in the group. A button's own prop still wins
densityshared'default' | 'compact'Horizontal padding for every button in the group
elevationshared0 | 1 | 2 | 3Drop shadow depth for every button in the group
orientationshared'horizontal' | 'vertical''horizontal'Which way the buttons run. Vertical flattens the top and bottom corners instead
disabledbooleanDisables every button in the group at once
fullWidthbooleanfalseStretches to the container and divides the width evenly between the buttons
childrenReactNodeThe buttons. The shared props reach them even through a wrapper

Every native <div> attribute passes straight through, minus color.

Examples

Shared props

Two things are happening here, and only one of them is visual. The corners are the look; the other half is that variant, size, color, density, elevation and disabled are stated once rather than repeated on every button. A group where one button is a size out is the failure this exists to prevent.

A button's own prop still wins — a row of secondary actions with one danger button in it is a real thing.

Orientation

Full width

How the seam works

Only the outline group pulls its buttons together by a pixel. Two hairline borders meeting would otherwise draw a seam twice as heavy as every other edge on the page, so the second button is shifted back to share a single line.

A solid group must not do that. Its seam is the plate edge — the white inset hairline every filled surface carries — and overlapping would put one button's fill over the neighbour's edge and merge the run into one blob.

Accessibility

  • Renders role="group". Give it an aria-label when the buttons alone do not say what the set is for.
  • This is not a segmented control and it does not manage selection. For one-of-a-set, use a RadioGroup — that is what that actually is.
  • The hovered or focused button is raised above its neighbours so its focus ring is never clipped.

Released under the MIT License