Skip to content

Segmented control

A row of buttons for switching between two to five related options, such as views or periods. Exactly one is pressed. To show different panels, use Tabs.

$12 per month

Code
demo.tsx
import {Stack, Text, SegmentedControl} from '@earendil-works/elanor-react';
import {useState} from 'react';

export default function SegmentedControlDemo() {
  const [period, setPeriod] = useState(['monthly']);

  return (
    <Stack gap="small" align="start">
      <SegmentedControl.Root
        aria-label="Billing period"
        value={period}
        onValueChange={(next) => {
          if (next.length > 0) setPeriod(next);
        }}
      >
        <SegmentedControl.Item value="monthly">Monthly</SegmentedControl.Item>
        <SegmentedControl.Item value="yearly">Yearly</SegmentedControl.Item>
      </SegmentedControl.Root>
      <Text role="status">{period[0] === 'yearly' ? '$120 per year' : '$12 per month'}</Text>
    </Stack>
  );
}

Usage

import {SegmentedControl} from '@earendil-works/elanor-react';

<SegmentedControl.Root aria-label="Billing period" defaultValue={['monthly']}>
  <SegmentedControl.Item value="monthly">Monthly</SegmentedControl.Item>
  <SegmentedControl.Item value="yearly">Yearly</SegmentedControl.Item>
</SegmentedControl.Root>;

The value is an array with one item, as in Base UI Toggle Group. Pressing the selected item would clear it; ignore empty values in onValueChange to keep one selected, as the demo does.

Density

Use compact on Root beside compact controls, such as Dropdown filters in a search and filter bar. Each item’s touch target keeps the default height, as on compact Dropdown triggers.

Code
density.tsx
import {SegmentedControl, Stack} from '@earendil-works/elanor-react';

export default function SegmentedControlDensity() {
  return (
    <Stack direction="row" gap="large" wrap="wrap">
      {(['default', 'compact'] as const).map((density) => (
        <SegmentedControl.Root
          key={density}
          density={density}
          aria-label={density === 'default' ? 'Billing period, default' : 'Billing period, compact'}
          defaultValue={['monthly']}
        >
          <SegmentedControl.Item value="monthly">Monthly</SegmentedControl.Item>
          <SegmentedControl.Item value="yearly">Yearly</SegmentedControl.Item>
        </SegmentedControl.Root>
      ))}
    </Stack>
  );
}

API

SegmentedControl.Root

PropTypeDefaultDescription
orientation'horizontal'-Only horizontal is supported.
multiplefalse-One item is pressed at a time.
density'compact' | 'default''default'compact removes the items' block padding but keeps their touch target height.

Also accepts Base UI ToggleGroup props.

SegmentedControl.Item

PropTypeDefaultDescription
type'submit' | 'reset' | 'button''button'

Also accepts Base UI Toggle props.