Browse all of Kata

Segmented control

Source docs/design/components/segmented-control.mdMarkdown

On this page

A connected track of equal segments that switches a view in place. The chosen segment is red.

Light

First selected

UpcomingPast

Second selected

UpcomingPast

With counts

Open3Mine1Done

Focus on an unselected segment

EveryoneInstructors

Dark

First selected

UpcomingPast

Second selected

UpcomingPast

With counts

Open3Mine1Done

Focus on an unselected segment

EveryoneInstructors

Source: 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.focus ring around the focused segment.
  • Pressed: the target is opacity.pressed 0.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 button with accessibilityState={{ selected }} and the label as its name, so "Upcoming, selected" is read.
  • brand.onRed on brand.red is 5.00:1 in both themes. border.control on surface.card is 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"
/>