SegmentControl

Радио-группа с единственным выбором, оформленная как сегментированный контрол. Подходит для переключения режимов отображения, фильтров с малым числом значений и компактных табов на плотных поверхностях. Поддерживает controlled и uncontrolled режим, клавиатурную навигацию (Arrow/Home/End с пропуском disabled), иконки, счётчики и режим полной ширины.

Когда использовать

  • Когда вариантов от 2 до 5 и все они одновременно видимы на экране.
  • Для переключения режимов отображения (list/grid/kanban, day/week/month).
  • Для компактных фильтров с взаимоисключающим выбором.

Когда не нужен SegmentControl:

  • Вариантов больше 5:
    • используйте Tabs или Select.
  • Допускается множественный выбор:
    • используйте чекбоксы или ToggleGroup.
  • Выбор приводит к загрузке тяжёлого контента и нужны отдельные урлы:
    • используйте Tabs.

Анатомия

Size (default m)

Размерный ряд: s / m / l — стандартные плотности.

Width (default auto)

  • auto — ширина по контенту.
  • full — растягивает контейнер на всю ширину родителя, сегменты делят ширину поровну. Уместен в формах и фильтрах с фиксированной шириной поля.

Outline (default false)

Булевый флаг — добавляет обводку контейнеру. Используется на «лёгких» поверхностях, где контрол должен явно отделяться от фона.

Segment slots

Каждый элемент items[i] собирается из:

  • label — текст сегмента.
  • icon — иконка с iconPosition: 'before' | 'after'.
  • counter — счётчик после label.

Дополнительно:

  • Сегмент может быть icon-only (без label).
  • Отдельный сегмент можно сделать disabled — клавиатурная навигация его пропускает.

Установка

pnpm add @cloud-ru/ds-segment-control
import { SegmentControl } from '@cloud-ru/ds-segment-control'

Примеры использования

1. Базовый сценарий

1. Базовый сценарийUncontrolled режим через defaultValue — компонент сам хранит выбор
tsx
import { SegmentControl } from '@cloud-ru/ds-segment-control';

export function Basic() {
  return (
    <SegmentControl
      defaultValue='overview'
      items={[
        { value: 'overview', label: 'Overview' },
        { value: 'analytics', label: 'Analytics' },
        { value: 'reports', label: 'Reports' },
      ]}
    />
  );
}

2. Все размеры

2. Все размерыs / m / l
tsx
import { SegmentControl } from '@cloud-ru/ds-segment-control';

const items = [
  { value: 'one', label: 'One' },
  { value: 'two', label: 'Two' },
  { value: 'three', label: 'Three' },
];

export function Sizes() {
  return (
    <div style={{ display: 'flex', gap: 12, flexWrap: 'wrap', alignItems: 'center' }}>
      <SegmentControl size='s' defaultValue='one' items={items} />
      <SegmentControl size='m' defaultValue='one' items={items} />
      <SegmentControl size='l' defaultValue='one' items={items} />
    </div>
  );
}

3. С иконками и icon-only

3. С иконками и icon-onlylabel + icon, или icon без label для плотных тулбаров
tsx
import { HomeSVG, PlusSVG, SettingsSVG } from '@cloud-ru/ds-icons/interface/system';
import { SegmentControl } from '@cloud-ru/ds-segment-control';

export function WithIcons() {
  return (
    <div style={{ display: 'flex', gap: 12, flexWrap: 'wrap', alignItems: 'center' }}>
      <SegmentControl
        defaultValue='home'
        items={[
          { value: 'home', label: 'Home', icon: <HomeSVG /> },
          { value: 'settings', label: 'Settings', icon: <SettingsSVG /> },
          { value: 'add', label: 'Add', icon: <PlusSVG /> },
        ]}
      />
      <SegmentControl
        defaultValue='home'
        items={[
          { value: 'home', icon: <HomeSVG /> },
          { value: 'settings', icon: <SettingsSVG /> },
          { value: 'add', icon: <PlusSVG /> },
        ]}
      />
    </div>
  );
}

4. Со счётчиком

4. Со счётчикомcounter рендерится после label и переиспользует @cloud-ru/ds-counter
tsx
import { SegmentControl } from '@cloud-ru/ds-segment-control';

export function WithCounter() {
  return (
    <SegmentControl
      defaultValue='inbox'
      items={[
        { value: 'inbox', label: 'Inbox', counter: 12 },
        { value: 'drafts', label: 'Drafts', counter: 3 },
        { value: 'archive', label: 'Archive' },
      ]}
    />
  );
}

5. Полная ширина и outline

5. Полная ширина и outlinewidth='full' растягивает на родителя; outline даёт обводку контейнера
tsx
import { SegmentControl } from '@cloud-ru/ds-segment-control';

export function FullWidth() {
  return (
    <div style={{ width: 480, maxWidth: '100%' }}>
      <SegmentControl
        width='full'
        outline
        defaultValue='day'
        items={[
          { value: 'day', label: 'Day' },
          { value: 'week', label: 'Week' },
          { value: 'month', label: 'Month' },
          { value: 'year', label: 'Year' },
        ]}
      />
    </div>
  );
}

6. Disabled сегмент

6. Disabled сегментКлавиатурная навигация Arrow/Home/End пропускает заблокированные элементы
tsx
import { SegmentControl } from '@cloud-ru/ds-segment-control';

export function DisabledSegment() {
  return (
    <SegmentControl
      defaultValue='one'
      items={[
        { value: 'one', label: 'One' },
        { value: 'two', label: 'Two', disabled: true },
        { value: 'three', label: 'Three' },
      ]}
    />
  );
}

7. Controlled с useState

7. Controlled с useStatevalue + onChange когда нужен внешний источник правды
Selected: list
tsx
import { SegmentControl } from '@cloud-ru/ds-segment-control';
import { useState } from 'react';

export function Controlled() {
  const [view, setView] = useState<'list' | 'grid' | 'kanban'>('list');

  return (
    <div style={{ display: 'flex', gap: 12, flexWrap: 'wrap', alignItems: 'center' }}>
      <SegmentControl
        value={view}
        onChange={setView}
        items={[
          { value: 'list', label: 'List' },
          { value: 'grid', label: 'Grid' },
          { value: 'kanban', label: 'Kanban' },
        ]}
      />
      <span>Selected: {view}</span>
    </div>
  );
}

Props

Types

PropsSegmentControlProps
PropTypeDefaultRequiredDescription
classNamestringnoCSS-класс контейнера.
data-test-idstringno
defaultValueIdTypenoID выбранного по умолчанию сегмента (uncontrolled).
itemsSegment<Value>[]yesНабор сегментов.
namestringnoИмя поля (hidden input для формы).
onChange((value: Value) => void)noКолбек смены выбранного сегмента.
outlinebooleannoОбводка.
size"l" | "m" | "s"mnoРазмер компонента.
valueIdTypenoValue выбранного сегмента.
width"auto" | "full"autonoУправление шириной компонента.

Unions

Types

SegmentControlProps

Unions

Storybook

Figma