﻿---
description: Адаптивный компонент для выбора одного значения из списка опций.
tags: selection
---

<Overview group="forms">

# Select [tag:component]

Адаптивный компонент для выбора одного значения из списка опций. Автоматически переключается между компонентом
[`NativeSelect`](/components/native-select) (для мобильных устройств) и [`CustomSelect`](/components/custom-select) (в остальных случаях).

Связанные компоненты:

- [`NativeSelect`](/components/native-select)
- [`CustomSelect`](/components/custom-select)

</Overview>

{/* @example-description: Базовый адаптивный `Select` с предустановленным значением и списком опций. */}
<Playground style={{ width: 270 }}>
  ```jsx
  <Select
    defaultValue="2"
    options={[
      { value: '1', label: 'Опция 1' },
      { value: '2', label: 'Опция 2' },
      { value: '3', label: 'Опция 3' },
    ]}
  />
  ```
</Playground>

## Режим работы

Компонент поддерживает работу как в неконтролируемом режиме, так и контролируемом. Это стандартное поведение
React-компонентов, прочитать про это можно в [документации React](https://react.dev/reference/react-dom/components/input#controlling-an-input-with-a-state-variable).

Для использования неконтролируемого режима достаточно просто _не_ передавать `value` или передавать `defaultValue`, если
требуется задать значение по умолчанию.
Для контролируемого режима используйте связку свойств `value`/`onChange` для задания значения и его изменения.

```jsx
const colors = [
  {
    value: 'red',
    label: 'Красный',
  },
  {
    value: 'green',
    label: 'Зелёный',
  },
  {
    value: 'blue',
    label: 'Синий',
  },
];

// Неконтролируемое состояние
<Select options={colors} defaultValue="red" />;

// Контролируемое состояние
const [color, setColor] = React.useState('red');

<Select options={colors} value={color} onChange={(_, newColor) => setColor(newColor)} />;
```

## Состояния

### `disabled`

Свойство `disabled` блокирует взаимодействие с компонентом и добавляет визуальную индикацию недоступности.

{/* @example-description: `Select` в неактивном состоянии `disabled`. */}
<Playground style={{ maxWidth: 270 }}>
  ```jsx
  <Select options={[{ value: 'red', label: 'Красный' }]} defaultValue="red" disabled />
  ```
</Playground>

## Валидация

Свойство `status` используется для визуализации валидации компонента - некорректности заполненного поля (значение `"error"`)
или успешной валидации (значение `"valid"`).

> Если вы используете `Select` вместе с [`FormItem`](/components/form-item), вам достаточно указать свойство `status` только у
> [`FormItem`](/components/form-item).

{/* @example-description: Состояния валидации `Select` со статусами `error` и `valid`. */}
<Playground style={{ maxWidth: 270 }}>
  ```jsx
  <Select options={[{ value: 'red', label: 'Красный' }]} defaultValue="red" status="error" />
  <Select options={[{ value: 'green', label: 'Зеленый' }]} defaultValue="green" status="valid" />
  ```
</Playground>

## Тестирование (e2e) [#e2e]

Если `Select` отрисовывает `NativeSelect`, то достаточно передать `testId` через `data-*` аттрибут для поиска элемента на странице.
Если `Select` отрисовывает `CustomSelect`, то следуйте рекомендациям из раздела "Тестирование (e2e)" компонента `CustomSelect`.

```jsx
<View activePanel="select">
  <Panel id="select">
    <PanelHeader>Select</PanelHeader>
    <Group>
      <FormItem
        top="Администратор"
        htmlFor="select-id"
        bottom="Пример использования Select для выбора администратора из списка"
      >
        <Select
          id="select-id"
          placeholder="Не выбран"
          options={getRandomUsers(10).map((user) => ({
            label: user.name,
            value: user.id,
            avatar: user.photo_100,
          }))}
          renderOption={({ option, ...restProps }) => (
            <CustomSelectOption
              {...restProps}
              key={option.value}
              before={<Avatar size={24} src={option.avatar} />}
            />
          )}
        />
      </FormItem>
    </Group>
  </Panel>
</View>
```

## Доступность (a11y) [#a11y]

Старайтесь сопровождать элемент текстовым описанием, для корректной работы скринридеров.
Для этого необходимо вручную передавать некоторые параметры:

- При задании текстового описания с помощью элемента `label` передавайте `id` компонента в свойство `htmlFor` элемента `label`.
  Это позволит фокусироваться на компоненте кликом по заголовку и автоматически добавит имя компоненту для скринридеров.
- Если по какой-то причине текстовое описание компонента не получается обернуть в тэг `label`, то можно попробовать связать
  текстовое описание с компонентом через [aria-labelledby](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-labelledby).
  Для этого передайте `id` текстового элемента компоненту в свойство [aria-labelledby](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-labelledby).
- При отсутствии по дизайну у выпадающего списка текстового описания старайтесь всё же его добавлять,
  но прятать с помощью элемента `VisuallyHidden`, чтобы оно оставалось доступно для пользователей ассистивных технологий.
  В крайнем случае используйте [aria-label](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-label) аттрибут.
- При использовании вместе с `FormItem` следуйте рекомендациям раздела "Цифровая доступность" компонента `FormItem`.

Старайтесь сопровождать элемент свойством `placeholder`.

Пример рекомендуемого использования компонента `Select` с текстовым описанием:

- вместе с `label`

```jsx
<label htmlFor="select-id">Цвет</label>
<Select
  id="select-id"
  placeholder="Не выбран"
  options={[ id: 'red', name: 'Красный' ]}
/>
```

- вместе с `FormItem`

```jsx
<FormItem top="Цвет" htmlFor="select-id">
  <Select id="select-id" placeholder="Не выбран" options={[ id: 'red', name: 'Красный' ]} />
</FormItem>
```

- вместе с `VisuallyHidden` (используя `label` и `htmlFor`)

```jsx
<VisuallyHidden Component="label" htmlFor="select-id">Цвет</VisuallyHidden>
<Select
  id="select-id"
  placeholder="Не выбран"
  options={[ id: 'red', name: 'Красный' ]}
/>
```

- вместе с [aria-labelledby](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-labelledby)

```jsx
<span id="select-label-id">Цвет</span>
<Select
  aria-labelledby="select-label-id"
  placeholder="Не выбран"
  options={[ id: 'red', name: 'Красный' ]}
/>
```

- вместе с `VisuallyHidden` (используя [aria-labelledby](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-labelledby))

```jsx
<VisuallyHidden Component="span" id="select-label-id">Цвет</VisuallyHidden>
<Select
  aria-labelledby="select-label-id"
  placeholder="Не выбран"
  options={[ id: 'red', name: 'Красный' ]}
/>
```

- вместе с [aria-label](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes/aria-label)

```jsx
<Select aria-label="Цвет" placeholder="Не выбран" options={[ id: 'red', name: 'Красный' ]} />
```

## Свойства и методы [#api]

| Свойство | Тип | По умолчанию | Описание |
| --- | --- | --- | --- |
| `accessible` | `boolean` | `-` | **Deprecated**: Since 8.0.0. Будет удалено в 9.0.0.  Включает режим в котором выбранное значение `CustomSelect` читается скринридерами корректно. В данном режиме введенное в поле ввода значение не сбрасывается при потере фокуса. |
| `after` | `ReactNode` | `-` | Добавляет иконку справа.  Рекомендации:  - Используйте следующие размеры иконок `12` \| `16` \| `20` \| `24` \| `28`. - Используйте [IconButton](https://vkui.io/components/icon-button), если вам нужна иконка, реагируюущая на нажатие. |
| `afterAlign` | `FieldIconsAlign` | `-` | Вертикальное выравнивание иконки справа. |
| `align` | `AlignType` | `-` |  |
| `allowClearButton` | `boolean` | `-` | Если `true`, то справа будет отображаться кнопка для очистки значения. |
| `before` | `ReactNode` | `-` | Добавляет иконку слева.  Рекомендации:  - Используйте следующие размеры иконок `12` \| `16` \| `20` \| `24` \| `28`. - Используйте [IconButton](https://vkui.io/components/icon-button), если вам нужна иконка, реагирующая на нажатие. |
| `beforeAlign` | `FieldIconsAlign` | `-` | Вертикальное выравнивание иконки слева. |
| `ClearButton` | `ComponentType<CustomSelectClearButtonProps>` | `-` | Кастомная кнопка для очистки значения. Должна принимать обязательное свойство `onClick`. |
| `clearButtonTestId` | `string` | `-` | Передает атрибут `data-testid` для кнопки очистки. |
| `defaultValue` | `SelectValue` | `-` | См. `value`. |
| `dropdownAutoWidth` | `boolean` | `-` | Ширина раскрывающегося списка зависит от контента. |
| `dropdownOffsetDistance` | `number` | `-` | Отступ от выпадающего списка. |
| `emptyText` | `string` | `-` | Текст, который будет отображен, если приходит пустой `options`. |
| `fetching` | `boolean` | `-` | Если `true`, то в дропдауне вместо списка опций рисуется спиннер. При переданных `renderDropdown` и `fetching: true` "победит" `renderDropdown`. |
| `fetchingCompletedLabel` | `string \| ((optionsCount: number) => string)` | `-` | Текстовая метка для индикации завершения процесса загрузки данных для пользователей скринридерами. По умолчанию: `"Загружено опций: ${options.length}"`. |
| `fetchingInProgressLabel` | `string` | `-` | Текстовая метка для индикации процесса загрузки данных для пользователей скринридерами. По умолчанию: `"Список опций загружается..."`. |
| `filterFn` | `false \| FilterFn<OptionT>` | `-` | Функция для кастомной фильтрации. По умолчанию поиск производится по `option.label`. |
| `forceDropdownPortal` | `boolean` | `-` | Использовать Portal для рендеринга выпадающего списка. |
| `getRef` | `Ref<HTMLSelectElement>` | `-` | **Deprecated**: Since 7.9.0. Вместо этого используйте `slotProps={ select: { getRootRef: ... } }`. |
| `getRootRef` | `Ref<HTMLDivElement>` | `-` |  |
| `getSelectInputRef` | `Ref<HTMLInputElement>` | `-` | **Deprecated**: Since 7.9.0. Вместо этого используйте `slotProps={ input: { getRootRef: ... } }`.  Ref на внутрений компонент input. |
| `icon` | `ReactNode` | `-` | Иконка раскрывающегося списка. |
| `labelTextTestId` | `string` | `-` | Передает атрибут `data-testid` для элемента, внутри которого отображается текст выбранной опции `CustomSelect` или плейсхолдер. |
| `mode` | `"default" \| "plain"` | `-` | **Deprecated**: Будет удалено в 10.0.0, используйте `selectType`.  Режим отображения.  - `default` — показывает фон, обводку и, при наличии, текст-подсказку. - `plain` — показывает только текст-подсказку. |
| `multiline` | `boolean` | `-` | Флаг для включения многострочного режима. |
| `nativeSelectTestId` | `string` | `-` | **Deprecated**: Since 7.9.0. Вместо этого используйте `slotProps={ select: { 'data-testid': ... } }`.  Передает атрибут `data-testid` для нативного элемента `select`. |
| `noMaxHeight` | `boolean` | `-` | Отключает максимальную высоту по умолчанию. |
| `onChange` | `((e: ChangeEvent<HTMLSelectElement>, newValue: SelectValue) => void)` | `-` | Обработчик, срабатывающий при изменении выбранного значения. Вторым параметром прокидывается новое значение.  > ⚠️ Лучше использовать второй параметр при работе с компонентом. |
| `onClose` | `VoidFunction` | `-` | Обработчик закрытия выпадающего списка. |
| `onInputChange` | `((e: ChangeEvent<HTMLInputElement>) => void)` | `-` | Событие изменения текстового поля. |
| `onInputKeyDown` | `((e: KeyboardEvent<Element>, isOpen: boolean) => void)` | `-` | Обработчик события `keyDown` в поле ввода. |
| `onOpen` | `VoidFunction` | `-` | Обработчик открытия выпадающего списка. |
| `**options** \*` | `OptionT[]` | `-` | Список опций в списке. |
| `overscrollBehavior` | `"none" \| "auto" \| "contain"` | `-` | Поведение overscroll, подробнее можно почитать в [документации](https://developer.mozilla.org/en-US/docs/Web/CSS/overscroll-behavior). |
| `placeholder` | `string` | `-` | Текст-подсказка при отсутствии выбранного значения. |
| `popupDirection` | `PopupDirection` | `-` | Направление раскрытия выпадающего списка. |
| `renderDropdown` | `({ defaultDropdownContent, }: { defaultDropdownContent: ReactNode; }) => ReactNode` | `-` | Рендер-проп для кастомного рендера содержимого дропдауна. В `defaultDropdownContent` содержится список опций в виде скроллящегося блока. |
| `renderOption` | `(props: CustomSelectRenderOption<OptionT>) => ReactNode` | `-` | Рендер-проп для кастомного рендера опции. В объекте аргумента приходят [свойства опции](https://vkui.io/components/custom-select#custom-select-option-api).  > ⚠️  Важно: свойство опции `disabled` должно выставляться только через проп `options`. > Запрещается выставлять `disabled` проп опциям в обход `options`, иначе `CustomSelect` не будет знать об актуальном состоянии опции. |
| `searchable` | `boolean` | `-` | Если `true`, то при нажатии на `CustomSelect` в нём появится текстовое поле для поиска по `options`. По умолчанию поиск производится по `option.label`. |
| `selectType` | `SelectType` | `-` | Тип селекта, влияющий на отображение. |
| `slotProps` | `({ root?: (Omit<HTMLAttributes<HTMLDivElement>, "children"> & HasDataAttribute & HasRootRef<HTMLDivElement>); select?: (NativeHTMLSelectProps & ... 1 more ... & HasDataAttribute) \| undefined; } & { ...; }) \| undefined` | `-` | Свойства, которые можно прокинуть внутрь компонента: - `root`: свойства для прокидывания в корень компонента; - `select`: свойства для прокидывания в нативный `select`; - `input`: свойства для прокидывания в нативный `input`. |
| `status` | `"default" \| "error" \| "valid"` | `-` | Статус отображения поля в форме. |
| `value` | `SelectValue` | `-` | Выбранное значение.  > ⚠️  Важно: При прокидывании `undefined` компонент будет считаться `Uncontrolled`. > > Не используйте `undefined`, чтобы показать невыбранное состояние. Вместо этого используйте `null`. |

