Sakuga Back to Sakuga
Theme
Sound
Jump to a component

Core · Actions

SegmentedControl

SegmentedControl switches between two to four views of the same thing: series sections, Following / For you, reading direction.

@anicanon/sakuga/uiv1.0Used onWeb · iOS · Android

Live, from @anicanon/sakuga 2.0.0

Sakuga for iOS and Android is coming

Its glass example is native on iOS and Android, so it doesn’t draw on the web.

iOS

Coming soon

SegmentedControl for iOS is in the roughs. The tokens it will read are the ones on this page, the same on every platform.

Android

Coming soon

SegmentedControl for Android is in the roughs. The tokens it will read are the ones on this page, the same on every platform.

Use it for
Switching between two to four views of the same thing (series sections, Following and For you), or a setting with two to four named values.
Not for
  • Five options or moreSelect
  • One setting that is on or offSwitch
  • Narrowing a feed by kindChip
  • Going to another part of the productTabBar

Guidelines

  • 2–4 short options. More than four is a list, not a segment.
  • fill on the page; glass when it floats over artwork or video (the shorts feed).
  • With sound on, a new choice plays the choose sound, by press, key or slide; pressing the chosen segment is silent (README · Sound).
  • The selected segment uses segmented-item-active-bg, drawn as one indicator that slides to the new segment on motion-base; each segment is a button with aria-pressed, inside a group named by label.
  • With onChange, slide from the selected pill: it moves to the segment under the pointer, and letting go chooses that segment. It steps from segment to segment, rather than following the pointer exactly, so the label inside it always reads. A press still picks a segment.
SegmentedControlExample.jsxReact
import { useState } from 'react';
import { SegmentedControl } from '@anicanon/sakuga/ui';

export default function SegmentedControlExample() {
  const [value, setValue] = useState('Episodes');
  const [value2, setValue2] = useState('For you');
  return (
    <>
      <SegmentedControl
        label="Series sections"
        fullWidth
        value={value}
        onChange={setValue}
        options={[
          { label: 'Episodes' },
          { label: 'Shorts' },
          { label: 'Cast' },
          { label: 'World' },
        ]}
      />
      <img
        src="/art/eba-cinema.webp"
        alt=""
        style={{
          position: 'absolute',
          inset: 0,
          width: '100%',
          height: '100%',
          objectFit: 'cover',
        }}
      />
      <SegmentedControl
        label="Feed"
        variant="glass"
        value={value2}
        onChange={setValue2}
        options={[{ label: 'Following' }, { label: 'For you' }]}
      />
    </>
  );
}

PropsSegmentedControlProps

optionsrequired
{ label: string; value?: string; }[]
valuerequired
string
labelrequired
string
onChange
(value: string) => void
variant
'fill'
fill, on the page.
fullWidth
boolean
className
string
SegmentedControlExample.swiftiOS · coming soon
SegmentedControlExample.ktAndroid · coming soon

Each token reads a role, and the role lands on a value in each theme. Change the role and every component that reads it follows.

Colour

segmented-track-bgSegmentedControl: track.
bg-fill-subtleshade-a06rgba(11,10,16,0.06)
bg-fill-subtlewhite-a08rgba(255,255,255,0.08)
segmented-item-fgSegmentedControl: idle segments.
text-primaryneutral-925#0b0a10
text-primaryneutral-0#ffffff
segmented-item-active-bgSegmentedControl: the selected segment.
action-primaryneutral-925#0b0a10
action-primaryneutral-0#ffffff
segmented-item-active-fgSegmentedControl: the selected segment name.
text-inverseneutral-0#ffffff
text-inverseneutral-925#0b0a10
segmented-glass-bgSegmentedControl glass: track over artwork or video, in both themes.
bg-glass-mediaglass-dark-a42rgba(28,28,34,0.42)
bg-glass-mediaglass-dark-a42rgba(28,28,34,0.42)
segmented-glass-borderSegmentedControl glass: track edge.
border-glass-mediawhite-a16rgba(255,255,255,0.16)
border-glass-mediawhite-a16rgba(255,255,255,0.16)
segmented-glass-item-fgSegmentedControl glass: idle segments over artwork.
text-on-medianeutral-0#ffffff
text-on-medianeutral-0#ffffff
segmented-glass-active-bgSegmentedControl glass: selected segment over artwork.
action-medianeutral-0#ffffff
action-medianeutral-0#ffffff
segmented-glass-active-fgSegmentedControl glass: selected segment name over artwork.
text-on-action-medianeutral-925#0b0a10
text-on-action-medianeutral-925#0b0a10

Space and shape

segmented-height
size-control-md
44px
segmented-padding
inset-xs
4px
segmented-radius
radius-full
9999px
segmented-glass-blur
blur-glass
blur(22px) saturate(1.8)
segmented-glass-inset-ring-width
line-hairline
1px
segmented-button-padding-x
inset-lg
16px
segmented-button-radius
radius-full
9999px
segmented-button-active-scale
scale-press-sm
.94
segmented-glide-radius
radius-full
9999px
segmented-forced-edge-width
line-hairline
1px

Type

segmented-font-family
font-sans
Funnel Sans
segmented-button-font
text-label
600 14px/20px "Funnel Sans", system-ui, -apple-system, "Segoe UI", sans-serif

Motion

segmented-button-background-color-duration
motion-base
240ms
segmented-button-easing
ease-standard
cubic-bezier(0.2, 0, 0, 1)
segmented-button-duration
motion-fast
160ms
segmented-button-active-duration
motion-instant
100ms

Checked automatically with axe-core 4.11.4 against WCAG 2.2 A and AA, on the live preview above, in light and dark, on 26 October 2026.

Result
No issues found, in light or in dark.
By design
Tab focuses each option; Enter or Space picks it. A screen reader hears the group's label, then each option as a button, "pressed" when selected. Dragging the pill is for the pointer; Enter or Space on an option does the same.
Not tested
The automated check doesn't test keyboard use, focus order or what a screen reader says. The lines above are the design system's own account of them.