ChipChoice.Custom

Чип-фильтр, в выпадающем меню которого рендерится произвольный контент через проп content. Подходит для сценариев, которые не покрываются готовыми вариантами Single / Multiple / Date / Time.

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

  • Когда контент выпадающего меню — нестандартный: вложенная форма, слайдер диапазона, кастомный список с группировкой.
  • Когда нужно полностью контролировать разметку и логику выбора значения.

Когда не нужен ChipChoice.Custom:

  • Для одиночного или множественного выбора из списка — используйте Single / Multiple.
  • Для дат и времени — Date / DateRange / Time.

Анатомия

Size (default s)

  • s — для плотных строк фильтров.
  • m — стандартный размер.
  • l — для крупных форм.

Content

Проп content получает объект CustomContentRenderProps и возвращает контент выпадающего меню:

  • value — текущее значение компонента.
  • onChange(value) — применить новое значение.
  • closeDroplist() — закрыть меню и вернуть фокус на чип.

Отображение выбранного значения в самом чипе задаёт valueRender(value).

Состояния

  • disabled — отключает взаимодействие.
  • loading — показывает спиннер вместо иконки.

Установка

pnpm add @cloud-ru/ds-chips
import { ChipChoice } from '@cloud-ru/ds-chips'

ChipChoice использует портал для выпадающего меню — оберните дерево в PortalContextProvider из @cloud-ru/ds-portal-context.

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

Произвольное меню

Произвольное менюcontent рендерит свой список, onChange + closeDroplist применяют выбор
tsx
import { Button } from '@cloud-ru/ds-button';
import { ChipChoice } from '@cloud-ru/ds-chips';
import { useState } from 'react';

const PRIORITIES = [
  { value: 'low', label: 'Низкий' },
  { value: 'medium', label: 'Средний' },
  { value: 'high', label: 'Высокий' },
];

export function ChoiceCustomBasic() {
  const [value, setValue] = useState<string | undefined>(undefined);

  return (
    <ChipChoice.Custom
      label='Приоритет'
      value={value}
      onChange={setValue}
      valueRender={current => PRIORITIES.find(item => item.value === current)?.label ?? null}
      content={({ closeDroplist, onChange }) => (
        <div style={{ display: 'flex', flexDirection: 'column', gap: 4, padding: 8 }}>
          {PRIORITIES.map(item => (
            <Button
              key={item.value}
              view='function'
              appearance='neutral'
              label={item.label}
              onClick={() => {
                onChange?.(item.value);
                closeDroplist();
              }}
            />
          ))}
        </div>
      )}
    />
  );
}

Props

Types

PropsChipChoiceCustomProps
PropTypeDefaultRequiredDescription
classNamestringnoCSS-класс
content((props: CustomContentRenderProps<any>) => ReactNode)noКонтент выпадающего меню
data-test-idstringno
disabledbooleannoОтключён
dropDownClassNamestringno
iconReactNodenoИконка
labelstringnoТекст чипа
loadingbooleannoСостояние загрузки
onChange((value: any) => void)noКолбек смены значения
onClearButtonClickMouseEventHandler<HTMLButtonElement>noКолбек для клика по кнопке очистки
onClickMouseEventHandler<HTMLButtonElement | HTMLDivElement>noКолбек обработки клика
onOpenChange((isOpen: boolean) => void)noКолбек отображения компонента
openbooleannoУправляет состоянием показан/не показан
placement"bottom" | "bottom-end" | "bottom-start" | "left" | "left-end" | "left-start" | "right" | "right-end" | "right-start" | "top" | "top-end" | "top-start"bottom-startnoРасположение выпадающего меню
size"l" | "m" | "s"mnoРазмер
tabIndexnumbernoИндекс в порядке фокусировки
truncateVariant"end" | "middle"'middle'noВариант обрезания строки Вариант обрезания значения
valueanynoФактическое значение
valueRender((value: any) => ReactNode)noОтображаемое значение
widthStrategy"auto" | "eq" | "gte"gtenoСтратегия управления шириной контейнера поповера

Storybook

Figma

Смотри также