Skip to content

SegmentedButton

Joins two or three choices into one control, with exactly one taken. Use it for short labels where every option should stay visible in little space.

tsx
import { Segment, SegmentedButton } from 'neba';

<SegmentedButton aria-label="Range" defaultValue="week">
  <Segment value="day">Day</Segment>
  <Segment value="week">Week</Segment>
  <Segment value="month">Month</Segment>
</SegmentedButton>;

Props

SegmentedButton

PropTypeDefaultDescription
variantshared'solid' | 'outline' | 'text''outline'Weight of the trough. `solid` is a frosted trough with a filled tile, `outline` the same with a hairline and a lit tile, `text` no trough at all
sizeshared'xs' | 'sm' | 'md' | 'lg' | 'xl''md'The segments' height and type scale, on Button's own ladder
colorshared'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info''primary'Semantic colour role. Arbitrary colour values are not accepted
densityshared'default' | 'compact''default'Padding only: never the height, never the type scale
elevationshared0 | 1 | 2 | 30Drop shadow depth of the trough. `0` is the default
valuestring | number | nullThe chosen segment, for a controlled set
defaultValuestring | number | nullnullWhich starts chosen
onValueChange(value: string | number | null) => voidCalled when the chosen segment changes
disabledbooleanfalseDisables every segment at once
readOnlybooleanfalseShows which one is chosen but does not let it be changed
namestringIdentifies the value when a form is submitted
fullWidthbooleanfalseThe segments share the full width, each taking an equal part
childrenReactNodeThe Segments

value with onValueChange makes it controlled; defaultValue makes it uncontrolled. The set needs a name, so pass aria-label or aria-labelledby.

Segment

PropTypeDefaultDescription
value * string | numberIdentifies the segment. What onValueChange reports
startIconReactNodeContent before the label
endIconReactNodeContent after the label: a count, a status dot
disabledbooleanfalseUnavailable, but still part of the set
childrenReactNodeThe segment's label

Examples

variant

solid rides a filled tile in a trough. outline is the same trough with a border, lighting the chosen sheet instead of filling it. text drops the trough and gives a surface only to the chosen segment.

size

The same control heights as Button: a md segment and a md button are both 32px, so the two sit in one toolbar without the row losing its baseline.

startIcon · disabled · readOnly

readOnly shows which one is chosen but does not let it change, draining the saturation. disabled drops the colour family for neutral grey. disabled can also be set per Segment.

fullWidth

Stretches the set to the container width, with the segments sharing the space equally.

Accessibility

  • Renders role="radiogroup". The set takes one tab stop, the arrow keys move within it, and the chosen segment carries aria-checked.
  • The selection tile moves via left · top · width · height, so no label is resampled. The first render and a window resize are not animated.

When to use something else

  • A row of actions rather than a choice is a ButtonGroup.
  • More than about five options, or long labels, wants a Select.
  • If there are panels underneath, it is Tabs.
  • If the set needs a visible label, a RadioGroup fits better.

Released under the MIT License