Skip to content

Segmented Control

Choose one option from a small set, with the selection always visible.

import { SegmentedControl, SegmentedControlItem } from '@youj/react'

Installation & usage

npm i @youj/react

For an app already set up with npx @youj/cli init, which installs the peers (@youj/core, @youj/motion, motion and Base UI) and wires the provider. New app? Start at Installation.

Use a segmented control for a small, fixed set of options where one is always chosen and the choice changes a view in place: a time range, a billing period, a layout. It's a thin wrapper over Toggle Group's segmented look (plain labels on a hairline, a 2px accent bar under the pressed one) with a simpler contract: the value is one string, and it can't be emptied.

Reach for something else when the shape is different:

  • Toggle Group when several options can be on at once (bold, italic, underline), or when the choice may be cleared.
  • Tabs when each option owns a panel of content that the others hide.
  • Radio Group for a choice inside a form that's submitted later.
  • Select when there are more options than fit in a row.
import { SegmentedControl, SegmentedControlItem } from '@youj/react'

export function RangePicker() {
  const [range, setRange] = useState('7d')
  return (
    <SegmentedControl aria-label="Range" value={range} onValueChange={setRange}>
      <SegmentedControlItem value="24h">24h</SegmentedControlItem>
      <SegmentedControlItem value="7d">7d</SegmentedControlItem>
      <SegmentedControlItem value="30d">30d</SegmentedControlItem>
    </SegmentedControl>
  )
}

onValueChange receives the pressed segment's value as a string. Pressing the segment that's already pressed does nothing, so there's always a choice. variant="pill" sets the segments in a recessed track with a raised key instead, which suits a control that sits inside a capsule or on a well. Leave defaultValue out to start with nothing pressed; the first press picks one.

Reference

Propsvalue, defaultValue, onValueChange… (8)

Props

SegmentedControl

SegmentedControl props
PropType
variant'underline' | 'pill'

underline (a bar on a hairline) or pill (a raised key in a recessed track).

default 'underline'

'underline'
valuestring

The pressed segment's value (controlled).

–
defaultValuestring

The segment pressed at first (uncontrolled). Leave it out to start with none pressed.

default ''

''
onValueChange(value: string) => void

Called with the newly pressed segment's value. Never called with an empty value.

–
aria-labelstring

Names the control for assistive tech, e.g. "View" or "Range".

–
soundboolean

With sound on (YoujProvider’s sound), a new choice plays select. false keeps this one silent.

default true

true
size'default' | 'sm' | 'lg'–
Other props pass through: extends ToggleGroupProps.

It also takes Toggle Group's size, orientation, loopFocus and disabled, and the props of a div.

SegmentedControlItem

SegmentedControlItem props
PropType
size'default' | 'sm' | 'lg'–
valueRequiredstring

The value this segment stands for.

–

Each segment takes a value and disabled, and the props of a button.

MotionIndicator, indicator appears, press… · reduced motion

Motion

Motion tokens
MomentTokens
Indicatorglides to the pressed segment and retargets if you press again mid-glide
spring.smooth

0.36s, bounce 0

0.36s, bounce 0
Indicator appearswhen a control with no value gets its first
duration.fastease.standard

140ms · cubic-bezier(0.2, 0, 0, 1)

140mscubic-bezier(0.2, 0, 0, 1)
Presseach segment scales to 0.97 while held
duration.instantease.standard

80ms · cubic-bezier(0.2, 0, 0, 1)

80mscubic-bezier(0.2, 0, 0, 1)
Hover and text color
duration.fastease.standard

140ms · cubic-bezier(0.2, 0, 0, 1)

140mscubic-bezier(0.2, 0, 0, 1)

Reduced motion

The indicator jumps to the pressed segment, and segments don't scale when pressed.

The bar (or the key, in pill) is one Sliding Indicator: transform-only layout projection, so its corners stay round in flight and nothing around it reflows. Resizes and font loads move it into place without animating.

Reduced motion

The indicator moves straight to the pressed segment, and presses don't scale. Which segment is pressed reads exactly the same.

AccessibilityKeyboard, ARIA, focus

Accessibility

  • The control is a group named by its aria-label, and each segment is a <button> with aria-pressed.
  • It's a single tab stop. The arrow keys move between segments and wrap at the ends, Home and End jump to the first and last, and Space or Enter presses the focused one.
  • The indicator is decorative (aria-hidden), so roving focus only visits real segments.
  • Name icon-only segments with aria-label.