ConfigSelector
Chip-toggle для выбора опции конфигурации. Под капотом — скрытый <input type=checkbox> в <label>: chip кликабелен целиком, поддерживает фокус с клавиатуры и tooltip-подсказки. Компонент controlled — состояние checked хранится снаружи.
Когда использовать
- Выбор одного значения из набора equal-weight опций конфигурации (тариф, размер инстанса, регион), когда их удобно показать рядом как chips.
- Когда у опции нужно подсветить «рекомендованность» (
available) или объяснить недоступность (disabled) через tooltip.
Когда не нужен ConfigSelector:
- Бинарная настройка с заголовком и описанием:
- используйте
SwitchRow.
- используйте
- Множественный выбор тегов/фильтров:
- используйте
Chip/Tag.
- используйте
Анатомия
Состояния
checked— выбранная опция: светло-зелёный tint (activated state-layer), accent-обводка, тёмно-зелёный текст. Управляется черезchecked+onChange(checked, e).available— accent-обводка для рекомендуемой опции. ОпциональноavailableTip— tooltip, который показывается, пока опция не выбрана.disabled— клики игнорируются. ОпциональноdisabledTip— tooltip-объяснение.
Слоты
label— обязательный текст chip. Длинный лейбл обрезается многоточием.
Доступность
Компонент основан на скрытом checkbox — это корректно для одиночного toggle (независимое вкл/выкл).
Для группового single-select (несколько ConfigSelector с checked ровно у одного, см. пример «Группа с single-select») семантика остаётся checkbox: скринридер озвучивает каждый chip как «checkbox» без контекста «1 из N». Checkbox-семантика выбрана осознанно — компонент переиспользуется в обоих сценариях и не навязывает radio-группу.
Если групповой контекст для скринридера обязателен, набор chip оборачивается в контейнер с role='radiogroup' и доступным именем (aria-label / aria-labelledby); ARIA-роль элементов при этом остаётся на стороне потребителя.
Установка
pnpm add @cloud-ru/ds-uikit-product-config-selector
import { ConfigSelector } from '@cloud-ru/ds-uikit-product-config-selector'
Примеры использования
Базовый ConfigSelector
import { ConfigSelector } from '@cloud-ru/ds-uikit-product-config-selector';
import { useState } from 'react';
export function Basic() {
const [checked, setChecked] = useState(false);
return <ConfigSelector label='Авторазвёртывание' checked={checked} onChange={setChecked} />;
}Рекомендуемая опция (available + tooltip)
import { PortalContextProvider } from '@cloud-ru/ds-portal-context';
import { ConfigSelector } from '@cloud-ru/ds-uikit-product-config-selector';
import { useState } from 'react';
export function Available() {
const [checked, setChecked] = useState(false);
return (
<PortalContextProvider>
<ConfigSelector
label='Рекомендуемый тариф'
available
availableTip='Подходит для большинства проектов'
checked={checked}
onChange={setChecked}
/>
</PortalContextProvider>
);
}Disabled с tooltip-объяснением
import { PortalContextProvider } from '@cloud-ru/ds-portal-context';
import { ConfigSelector } from '@cloud-ru/ds-uikit-product-config-selector';
import { useState } from 'react';
export function Disabled() {
const [checked, setChecked] = useState(false);
return (
<PortalContextProvider>
<ConfigSelector
label='Премиум-конфигурация'
disabled
disabledTip='Недоступно на текущем тарифе'
checked={checked}
onChange={setChecked}
/>
</PortalContextProvider>
);
}Группа с single-select
import { ConfigSelector } from '@cloud-ru/ds-uikit-product-config-selector';
import { useState } from 'react';
const OPTIONS = ['nano', 'micro', 'standard', 'large'] as const;
export function Group() {
const [selected, setSelected] = useState<(typeof OPTIONS)[number]>('micro');
return (
<div style={{ display: 'flex', gap: 12, flexWrap: 'wrap', alignItems: 'center' }}>
{OPTIONS.map(option => (
<ConfigSelector
key={option}
label={option}
checked={selected === option}
onChange={() => setSelected(option)}
/>
))}
</div>
);
}Props
Types
ConfigSelectorProps| Prop | Type | Default | Required | Description |
|---|---|---|---|---|
available | boolean | — | no | Доступна ли опция |
availableTip | ReactNode | — | no | Тултип для доступной опции |
checked | boolean | — | yes | Отмечен ли компонент |
className | string | — | no | CSS-класс |
data-test-id | string | — | no | |
disabled | boolean | — | no | Деактивирован ли компонент |
disabledTip | ReactNode | — | no | Тултип для деактивированного компонента |
label | string | — | yes | Лейбл |
onChange | (checked: boolean, e: ChangeEvent<HTMLInputElement>) => void | — | yes | Колбек смены значения |
tabIndex | number | 0 | no | HTML tab index |