ButtonGroup

Segmented controls, split buttons, attached groups.
On the web the segmented control is Dark Factory's: the options sit in a pill track and the selected one rides a white thumb, with the rest in the muted ink. The split button is the green call-to-action pill with its chevron half, and the stepper and the spaced peers are hairline pills the height of a Button beside them. On iOS and Android the groups keep their platform shapes (the iOS segmented control, the Material 3 segmented button) in the theme's colours.
All four kinds follow the theme's surface mode. Toggle Liquid Glass in the docs, or use <ThemeProvider glass> in an app: segmented groups paint a glass selection pill on the selected segment, a split group is its call to action's brand-tinted glass (the action colour under the material, as a primary Button), a stepper shares a glass capsule, and spaced peers get individual glass surfaces. Solid mode keeps each platform's existing skin. The material uses native Liquid Glass on supported iOS versions, the native blur or tint fallback on Android and older iOS, and Dark Factory's frost in the browser. Reduce Transparency and Increase Contrast use the shared material's opaque fallbacks.
iOS
Android
Web
tsx
<ButtonGroup items={["Day", "Week", "Month"]} />

Props

Prop
Description
items
ButtonGroupItem[]
Segments for segmented/spaced: a label string, or `{ label, icon }` for a leading kit glyph. The stepper cycles the labels (icons ignored there).
active
number
Selected segment index (segmented, CONTROLLED), or the stepper's initial index. Omit for uncontrolled use.
defaultActive
number
Initial selected segment index for uncontrolled use (a bare segmented control selects on press).
onSelect
(index: number, item: string, event: GestureResponderEvent) => void
Called with the pressed/selected index and item (and, for the stepper, the new index).
segmented
boolean
Kind (pick one; default is segmented).
split
boolean
Kind (pick one; default is segmented).
stepper
boolean
Kind (pick one; default is segmented).
spaced
boolean
Kind (pick one; default is segmented).
menu
string[]
Related actions shown in the split kind's chevron dropdown.
small
boolean
Size (pick one; default is the medium size).
large
boolean
Size (pick one; default is the medium size).
iconsOnly
boolean
Segmented/spaced only: each segment renders its `icon` alone and the item's `label` becomes the segment's ACCESSIBLE name (an icon-only view or form-factor switcher). An item without an icon keeps its visible label, with a dev-only warning. Split and stepper ignore it (dev-only warning).
accessibilityLabel
string
Accessible name for the segmented row (the `tablist`), announcing what the group switches (e.g. "Preview form factor"). Segmented kind only: spaced peers are independent buttons with no group role.
block
boolean
Stretch the group to the container width, the segments sharing the space equally. An orthogonal layout modifier for the segmented and spaced kinds; split and stepper ignore it (their cells are fixed-width chrome) with a dev-only warning. A measure step (`sm`, `lg`, …) does the same up to that width of the scale.
disabled
boolean
—
testID
string
E2E hook forwarded to the root element.
style
LayoutStyle
Composition within a parent only, never a restyle hook and never a width: the parent layout container provides the bounds.
xxxs
boolean
Measure (pick one; omit to take the parent's bounds). Caps the component at a step of the width scale, centered in its column; `start` pins it to the leading edge.
xxs
boolean
Measure (pick one; omit to take the parent's bounds). Caps the component at a step of the width scale, centered in its column; `start` pins it to the leading edge.
xs
boolean
Measure (pick one; omit to take the parent's bounds). Caps the component at a step of the width scale, centered in its column; `start` pins it to the leading edge.
sm
boolean
Measure (pick one; omit to take the parent's bounds). Caps the component at a step of the width scale, centered in its column; `start` pins it to the leading edge.
md
boolean
Measure (pick one; omit to take the parent's bounds). Caps the component at a step of the width scale, centered in its column; `start` pins it to the leading edge.
lg
boolean
Measure (pick one; omit to take the parent's bounds). Caps the component at a step of the width scale, centered in its column; `start` pins it to the leading edge.
xl
boolean
Measure (pick one; omit to take the parent's bounds). Caps the component at a step of the width scale, centered in its column; `start` pins it to the leading edge.
xxl
boolean
Measure (pick one; omit to take the parent's bounds). Caps the component at a step of the width scale, centered in its column; `start` pins it to the leading edge.
xxxl
boolean
Measure (pick one; omit to take the parent's bounds). Caps the component at a step of the width scale, centered in its column; `start` pins it to the leading edge.
wide
boolean
Measure (pick one; omit to take the parent's bounds). Caps the component at a step of the width scale, centered in its column; `start` pins it to the leading edge.
wider
boolean
Measure (pick one; omit to take the parent's bounds). Caps the component at a step of the width scale, centered in its column; `start` pins it to the leading edge.
widest
boolean
Measure (pick one; omit to take the parent's bounds). Caps the component at a step of the width scale, centered in its column; `start` pins it to the leading edge.
page
boolean
Measure (pick one; omit to take the parent's bounds). Caps the component at a step of the width scale, centered in its column; `start` pins it to the leading edge.
start
boolean
Pin a capped component to the leading edge instead of centering it in its column.

Do & Don’t

Segmented

Don’t
Past ~4 options a segmented control gets cramped and hard to scan; reach for a select.
Do
Keep a segmented control to a few mutually-exclusive views.

Attached

Don’t
Attaching unrelated actions implies they belong to one control.
Do
Today
Reserve attached groups for closely-related actions like prev / today / next.

Split

Don’t
Save
With no divider the chevron looks like part of one button, hiding the menu.
Do
Separate the chevron with a hairline so the secondary menu reads as distinct.