SegmentedControl
iOS-style segmented selector with a sliding indicator.
Installation
npx axiom add segmented-controlpnpm dlx axiom add segmented-controlyarn dlx axiom add segmented-controlbun x axiom add segmented-controlInstalls: react-native-reanimated, react-native-worklets, react-native-gesture-handler.
Selection, measurement and the draggable indicator live in use-segmented-control.ts, shared by every styling variant. Colors come from segmentedControl.default.{default,selected,disabled}.{track,indicator,border,foreground} in the component tokens.
Usage
import { SegmentedControl } from "@/components/ui/segmented-control";
<SegmentedControl
options={["List", "Grid"]}
value={layout}
onValueChange={setLayout}
/>;Props
| Prop | Type | Default | Description |
|---|---|---|---|
options | Array<string | SegmentOption> | — | The segments. A string is used as both value and label. SegmentOption is { value, label?, icon?, accessibilityLabel?, disabled? }. |
value | string | — | Value of the selected segment. |
defaultValue | string | first option | Initial selection when the control manages its own state. |
onValueChange | (value: string) => void | — | Called when the user picks another segment. |
size | 'md' | 'lg' | 'md' | Minimum height: 32 or 40pt. Grows with larger system text. |
fullWidth | boolean | true | Stretches to the parent width with equal segments. false sizes it to its content. |
disabled | boolean | false | Disables the whole control. |
style | StyleProp<ViewStyle> | — | Extra styles for the track. |
The indicator slides on the UI thread with Reanimated and can be dragged from one segment to another. Keep it to 2–5 short options: past that, labels get truncated.
Use cases
Switching the view of the same data
The segments change how the content is shown, not what it is. Icons are enough when they are standard.
<SegmentedControl
fullWidth={false}
options={[
{ value: "list", icon: "menu", accessibilityLabel: "List" },
{ value: "grid", icon: "grid", accessibilityLabel: "Grid" },
]}
value={layout}
onValueChange={setLayout}
/>Filtering a list in place
A short list of states above the content. Changing segment filters the list below without navigating.
<SegmentedControl options={['All', 'Active', 'Delivered']} value={status} onValueChange={setStatus} />
<FlatList data={orders.filter(byStatus(status))} renderItem={renderOrder} />Setting with few options
A compact alternative to radios for 2–3 values that the user compares at a glance.
<SegmentedControl
size="lg"
options={[
{ value: "light", label: "Light", icon: "sun" },
{ value: "dark", label: "Dark", icon: "moon" },
{ value: "system", label: "Auto" },
]}
value={scheme}
onValueChange={setScheme}
/>Related
- Tab, for switching between content areas
- ButtonGroup
- Radio