A connected track of equal segments that switches a view in place. The chosen segment is red.
Light
First selected
UpcomingPastSecond selected
UpcomingPastWith counts
Open3Mine1DoneFocus on an unselected segment
EveryoneInstructorsDark
First selected
UpcomingPastSecond selected
UpcomingPastWith counts
Open3Mine1DoneFocus on an unselected segment
EveryoneInstructorsSource:
SegmentedControl.tsx.
When to use it
- Two to four short, mutually exclusive views of the same content: Upcoming / Past, Week / Month / Year, the lanes of the coaching hub.
- When switching is instant and loses nothing.
Not for five or more options, or labels longer than a word or two — use chips or a sheet. Not for navigation to a different screen. Not for a form value that is submitted later — use chips inside the form so the choice stays visible.
Anatomy
| Part | Token |
|---|---|
| Track | surface.card fill, 1px border.control, radius.pill |
| Track inset | spacing.s2 padding, spacing.s4 between segments |
| Segment | equal width, spacing.s8 padding, radius.pill |
| Label | 13/500, text.secondary; selected brand.onRed |
| Selected fill | brand.red |
| Count | an 18pt pill after the label, spacing.s6 gap; border.default fill on surface.card (the track), with text.secondary, inverted to brand.onRed with brand.red text on the selected segment |
States
- Selected: the red fill. Only one segment is selected at any time.
- Focus: a 2px
border.focusring around the focused segment. - Pressed: the target is
opacity.pressed0.85; the component does not draw one today. - Disabled, loading, error: none. If a view has nothing in it, show its empty state after the switch rather than hiding the segment.
Content
- One word per segment where possible, two at most. Labels are held to one line inside equal segments — the one place Kata allows a single line — so a long label is a design bug.
- A count says how many are waiting, not a total for decoration. Zero hides the count.
Accessibility
- Each segment is role
buttonwithaccessibilityState={{ selected }}and the label as its name, so "Upcoming, selected" is read. brand.onRedonbrand.redis 5.00:1 in both themes.border.controlonsurface.cardis 3.53:1 in light and 3.16:1 in dark, so the track's edge clears the 3:1 a control boundary owes.- Each segment is about 38pt tall drawn; the 2pt track inset and a 44pt row around it bring the target to size.
Do and don't
WeekMonthYear
Do
Two to four short options that switch a view in place.
DayWeekMonthQuarterYearAll time
Don’t
Six options squeezed into equal segments. That is a picker.
Code
import { SegmentedControl } from '../../components/ui';
<SegmentedControl
options={[
{ value: 'upcoming', label: 'Upcoming', testID: 'events-upcoming' },
{ value: 'past', label: 'Past', testID: 'events-past' },
]}
value={view}
onChange={setView}
testID="events-view"
/>