﻿---
description: Компонент для отображения списка действий в виде всплывающего меню.
---

<Overview group="modals">

# ActionSheet [tag:component]

Компонент для отображения списка действий в виде всплывающего меню.
Поддерживает различные режимы отображения в зависимости от платформы и размера экрана. Например,
на платформе iOS компонент имитирует поведение [нативного](https://developer.apple.com/design/human-interface-guidelines/action-sheets/).
В качестве элементов списка принимает коллекцию [`ActionSheetItem`](#action-sheet-item).

</Overview>

<Playground hide>

```jsx
<ActionSheet mode="sheet" onClosed={() => {}}>
  <ActionSheetItem>Слушать далее</ActionSheetItem>
  <ActionSheetItem>Поделиться</ActionSheetItem>
  <ActionSheetItem>Скопировать ссылку</ActionSheetItem>
</ActionSheet>
```

</Playground>

{/* @example-description: Базовый пример использования ActionSheet. */}
<Playground>

```jsx
const [actionSheet, setActionSheet] = React.useState(null);
const targetRef = React.useRef(null);

function handleClose() {
  setActionSheet(null);
}

function handleOpen() {
  setActionSheet(
    <ActionSheet toggleRef={targetRef} onClosed={handleClose}>
      <ActionSheetItem>Слушать далее</ActionSheetItem>
      <ActionSheetItem>Поделиться</ActionSheetItem>
      <ActionSheetItem>Скопировать ссылку</ActionSheetItem>
    </ActionSheet>,
  );
}

return (
  <>
    {actionSheet}
    <Button getRootRef={targetRef} onClick={handleOpen} aria-expanded={Boolean(actionSheet)}>
      Туц-туц
    </Button>
  </>
);
```

</Playground>

При использовании данного компонента отталкивайтесь от контекста и количества действий.
Использование `ActionSheet` хорошо подходит для отображения вариантов в ответ на осознанное действие.
Например, при отмене редактирования электронного письма среди доступных вариантов могут быть такие действия как "Удалить изменения",
"Сохранить черновик" и "Вернуть к редактированию".

> По рекомендациям **Apple** следует избегать более четырёх действий в списке (включая действие "Отмена").

> Не используйте компонент для подтверждения действий или предупреждений. Для этого лучше всего подходит компонент `Alert`.

## Обязательные свойства

### `onClosed`

Свойство `onClosed` принимает функцию, которая вызовется после завершения анимации закрытия компонента.
Обязательно удаляйте из `DOM`-дерева компонент `ActionSheet` в обработчике `onClosed`, иначе в верстке останется
прозрачный элемент, который будет мешать дальнейшему взаимодействию с элементами и повторному открытию компонента.

Функция принимает объект с информацией о причине закрытия:

```jsx
function handleClosed({ closedBy }) {
  if (closedBy === 'action-item') {
    // закрытие произошло по выбору действия из списка
  } else if (closedBy === 'cancel-item') {
    // закрытие произошло по нажатию на кнопку отмены
  } else {
    // закрытие произошло по другим причинам (например, клик вне области всплывающего окна)
  }
}
```

### `toggleRef` (якорный элемент)

В данное свойство следует передавать элемент, относительно которого будет позиционироваться
компонент в `mode="menu"` (учитывая автоматическое определение режима).
В качестве значения лучше передавать [ref-объект](https://react.dev/learn/manipulating-the-dom-with-refs).

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

Задаётся свойством `mode`. По умолчанию отображение определяется в зависимости от размеров экрана.

- `"sheet"` — отображение снизу экрана в виде всплывающего окна (по умолчанию для мобильных устройств)
- `"menu"` — отображение в виде всплывающего элемента относительно якорного элемента (по умолчанию для десктопа)

## Шапка

В компоненте есть возможность задать заголовок и описание для списка с помощью свойств `title` и `description` соответственно.

```jsx
<ActionSheet title="Выберите действие" description="Это описание для списка действий">
  <ActionSheetItem>Действие 1</ActionSheetItem>
  <ActionSheetItem>Действие 2</ActionSheetItem>
  <ActionSheetItem>Действие 3</ActionSheetItem>
</ActionSheet>
```

## Позиционирование

### `placement`

Свойство `placement` отвечает за направление положения относительно якорного элемента.
Оно поддерживается только для `mode="menu"` (учитывая автоматическое определение режима).

Обратите внимание, что компонент выбирает наилучшее расположение самостоятельно,
а данное свойство задаёт только _приоритетное_ положение. Это означает, что в случае недостаточного места для позиционирования
по приоритетному положению, будет выбрано любое другое подходящее.

В качестве вариантов положения ориентируйтесь на значения из библиотеки [floating-ui](https://floating-ui.com/docs/tutorial#placements).

### `popupOffsetDistance`

Свойство `popupOffsetDistance` позволяет задать отступ (в пикселях) от якорного элемента.

## Браузерные события

### Click Event

По умолчанию событие `click` не всплывает, что позволяет изолировать компонент от остального приложения.
Если вам необходимо данное событие обрабатывать (например, у вас есть глобальный обработчик клика для сбора аналитики),
воспользуйтесь свойством `allowClickPropagation`.

## Управление фокусом

### `autoFocus`

Данное свойство позволяет автоматически устанавливать фокус на первом интерактивном элементе при открытии всплывающего элемента.
По умолчанию это поведение включено, но можно его отключить, передав `autoFocus={false}`.

Также есть возможность установить фокус на контейнере всплывающего меню, передав `autoFocus="root"`. Это может быть полезно,
когда первый интерактивный элемент имеет подсказку, которая активируется при фокусе. В таком случае появление подсказки сразу
после открытия всплывающего меню может быть нежелательным. Значение `"root"` позволяет поддержать данный сценарий, не ломая доступность.

### `restoreFocus`

Данное свойство позволяет восстанавливать фокус после закрытия всплывающего меню на последний активный элемент.
По умолчанию данное поведение включено, но можно его отключить, передав `restoreFocus={false}`.

Также есть возможность передать в `restoreFocus` функцию, которая возвращает `HTMLElement` или `boolean`.
Если возвращается `HTMLElement`, то фокус будет возвращен на этот элемент, при `false` — фокус не восстанавливается,
при `true` — поведение по умолчанию.

### `timeout`

Свойство позволяет задать задержку (в миллисекундах) при установке и восстановлении фокуса.

## Кнопка "Отмена" [#cancel-item]

Согласно рекомендациям **Apple** в `ActionSheet` должен быть вариант действия "Отмена", который
бы позволял закрывать всплывающее окно без выполнения дополнительных действий.

Используя свойство `iosCloseItem`, можно передать свой вариант элемента "Отмена", по умолчанию
используется компонент `ActionSheetDefaultIosCloseItem`.

> Данное свойство доступно только при выполнении следующих условий:
>
> - платформа iOS
> - `mode="sheet"` (учитывая автоматическое определение режима)

```jsx
import { ActionSheet, ActionSheetDefaultIosCloseItem } from '@vkontakte/vkui';

<ActionSheet
  iosCloseItem={<ActionSheetDefaultIosCloseItem>{cancelLabel}</ActionSheetDefaultIosCloseItem>}
>
  {/* ActionSheetItem */}
  {/* ActionSheetItem */}
  {/* ActionSheetItem */}
</ActionSheet>;
```

Также можно использовать свойство `slotProps.iosCloseItem` для передачи пропсов в `ActionSheetDefaultIosCloseItem`:

```jsx
<ActionSheet
  slotProps={{
    iosCloseItem: {
      children: cancelLabel,
    },
  }}
>
  {/* ActionSheetItem */}
  {/* ActionSheetItem */}
  {/* ActionSheetItem */}
</ActionSheet>;
```

## ActionSheetDefaultIosCloseItem [#action-sheet-default-ios-close-item]

Компонент для отображения кнопки "Отмена" в `ActionSheet` на платформе iOS.

Рекомендуется использовать этот компонент вместо устаревших `mode="cancel"` и `isCancelItem` в `ActionSheetItem`.

<Playground>
  ```jsx
  <ActionSheetDefaultIosCloseItem>Отмена</ActionSheetDefaultIosCloseItem>
  ```
</Playground>

## ActionSheetItem [#action-sheet-item]

Подкомпонент для отображения элемента всплывающего меню [`ActionSheet`](/components/action-sheet). Каждому компоненту можно задать различные режимы отображения,
добавлять иконки и метаданные.

<Playground>
  ```jsx
  <ActionSheetItem>Сохранить</ActionSheetItem>
  ```
</Playground>

### Цвет

Задаётся свойством `mode`.

#### `"default"`

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

<Playground>
  ```jsx
  <ActionSheetItem>Сохранить</ActionSheetItem>
  ```
</Playground>

#### `"destructive"`

Цвет критических действий (чаще всего красный), старайтесь располагать такие действия сверху списка,
где они наиболее заметны.

<Playground>
  ```jsx
  <ActionSheetItem mode="destructive">Удалить</ActionSheetItem>
  ```
</Playground>

#### ~`"cancel"`~

> **@deprecated** Since 8.0.0. Значение `"cancel"` устарело и будет удалено в **VKUI v10**.
> Используйте компонент [`ActionSheetDefaultIosCloseItem`](/components/action-sheet#action-sheet-default-ios-close-item) или передайте пропсы через `slotProps.iosCloseItem` в `ActionSheet`.

Цвет действия отмены.

<Playground>
  ```jsx
  <ActionSheetItem mode="cancel">Отмена</ActionSheetItem>
  ```
</Playground>

### ~Кнопка "Отмена"~

> **@deprecated** Since 8.0.0. Свойство `isCancelItem` устарело и будет удалено в **VKUI v10**.
> Используйте компонент [`ActionSheetDefaultIosCloseItem`](/components/action-sheet#action-sheet-default-ios-close-item) или передайте пропсы через `slotProps.iosCloseItem` в `ActionSheet`.

Свойство `isCancelItem` позволяет пометить пункт действия как "Отмена".

Согласно рекомендациям **Apple** в `ActionSheet` должен быть вариант действия "Отмена", который
бы позволял закрывать всплывающее окно без выполнения дополнительных действий.

> Обратите внимание, что такой компонент необходимо передавать в свойство `iosCloseItem` у `ActionSheet`,
> потому что данный компонент должен визуально отделяться от остальных пунктов.

Подробнее с использованием можно ознакомиться на странице [`ActionSheet`](/components/action-sheet#cancel-item).

### Текстовые элементы

Основной контент компонента (заголовок) можно задать, передав в свойство `children` необходимый текст:

<Playground>
  ```jsx
  <ActionSheetItem>Скорость воспроизведения</ActionSheetItem>
  ```
</Playground>

Свойство `subtitle` позволяет отобразить дополнительный текст под заголовком:

<Playground>
  ```jsx
  <ActionSheetItem subtitle="Обычная">Скорость воспроизведения</ActionSheetItem>
  ```
</Playground>

Свойство `meta` даёт возможность отобразить небольшой пояснительный текст или индикатор рядом с заголовком:

<Playground>
  ```jsx
  <ActionSheetItem meta={<Icon12Circle fill="var(--vkui--color_icon_negative)" />}>
    Закрепить запись
  </ActionSheetItem>
  ```
</Playground>

#### Многострочный режим

По умолчанию большое количество текста обрезается и заменяется на многоточие, поддерживая однострочный режим отображения.
Это поведение можно отключить (_для всех текстовых элементов_) с помощью свойства `multiline`:

<Playground style={{ maxWidth: 270 }}>
  ```jsx
  <ActionSheetItem multiline>
    Очень длинный заголовок просто для примера, старайтесь избегать такого
  </ActionSheetItem>
  ```
</Playground>

### Контент в начале/в конце

В компоненте доступна возможность добавления дополнительного контента слева и/или справа от текста,
задаётся свойством `before` и `after` соответственно.
Наиболее частый вариант использования свойств `before`/`after` - иконки или аватары.

В соответствии с рекомендациями дизайн-системы, для десктопного представления (`compact`-режим) следует
использовать иконки размером `20px`, для мобильного представления (`regular`-режим) — `28px`.
Проще всего это сделать, используя компонент [`AdaptiveIconRenderer`](/components/adaptive-icon-renderer).

<Playground>
  ```jsx
  <ActionSheetItem
    before={
      <AdaptiveIconRenderer IconCompact={Icon20WriteOutline} IconRegular={Icon28EditOutline} />
    }
  >
    Редактировать профиль
  </ActionSheetItem>
  ```
</Playground>

### Состояния

#### `disabled`

Свойство позволяет отключить возможность взаимодействия с пунктом меню.

<Playground>
  ```jsx
  <ActionSheetItem subtitle="Отсутствуют" disabled>
    Субтитры
  </ActionSheetItem>
  ```
</Playground>

#### `selectable`

Свойство даёт возможность выбирать элемент (визуальная и нативная имитация элемента радиокнопки).
При использовании данного свойства вы также можете передавать стандартные свойства радиокнопок, для управления поведением:

- `name` — имя группы для радиокнопок;
- `value` — значение радиокнопки;
- `defaultChecked` — установить выбранным по умолчанию;
- `checked` и [`onChange`](#onchange) — для контролируемого извне использования выбранного значения;

<Playground direction="column">

```jsx
const [filter, setFilter] = useState('Нормальная');

const onChange = (e) => {
  // e.target.value будет равно значению, переданному в `value` выбранного компонента `ActionSheetItem`
  setFilter(e.target.value);
};

return ['0.25x', '0.5x', '0.75x', 'Нормальная', '1.25x', '1.5x', '2x', '3x'].map((speed) => (
  <ActionSheetItem
    key={speed}
    onChange={onChange}
    checked={filter === speed}
    name="filter"
    value={speed}
    selectable
  >
    {speed}
  </ActionSheetItem>
));
```

</Playground>

Дополнительно через свойство `iconChecked` есть возможность изменить иконки радиокнопки, которая рисуется по умолчанию.

<Playground>
  ```jsx
  <ActionSheetItem
    defaultChecked
    selectable
    iconChecked={
      // квадратные иконки выбора
      <AdaptiveIconRenderer IconCompact={Icon20CheckBoxOn} IconRegular={Icon24CheckBoxOn} />
    }
  >
    0.75x
  </ActionSheetItem>
  ```
</Playground>

### Обработчики событий

#### `onClick`/ `onImmediateClick`

Нажатие на пункт меню можно обработать с помощью свойств `onClick` и `onImmediateClick`.

По умолчанию `onClick` будет вызван после завершения анимации скрытия всплывающего меню и после вызова `onClosed`.
Из этого следует, что в объекте события значение поля `currentTarget` будет не определено.
Если вам нужен объект события именно на момент нажатия, воспользуйтесь `onImmediateClick`.

> По умолчанию клик на пункт меню автоматически вызывает закрытие всплывающего меню (функцию, переданную в `onClosed` у `ActionSheet`).
>
> Если такое поведение нежелательно, то используйте свойство `autoCloseDisabled`. В таком случае закрытие всплывающего окна
> следует вызывать самостоятельно.

#### `onChange`

Если задано свойство `selectable={true}`, то выбор пункта следует обрабатывать с помощью свойства `onChange`.
Пример можно увидеть [выше](#selectable).

### Ссылки

Если указать свойство `href`, компонент будет рендериться как ссылка `<a>`.
Также можно задать стандартное свойство `target`:

```jsx
<ActionSheetItem href="https://vk.com" target="_blank">
  Перейти на vk.com
</ActionSheetItem>
```

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

- у `ActionSheet` уже заданы атрибуты `role="dialog"` и `aria-modal="true"`, потому что по умолчанию он появляется как диалог и,
  пока он не закроется, нельзя взаимодействовать с другими элементами на странице. Эти атрибуты можно переопределить, явно передавая
  их компоненту;
- у целевого элемента обязательно должен быть выставлен атрибут `aria-expanded`.
- при задании параметра `selectable={true}` для корректной работы важно задать всем `ActionSheetItem` одинаковое значение параметра
  `name`. Обусловлено это тем, что в реализации используется нативный `input[type='radio']` и по пунктам можно навигировать как по
  обычным `radio`-кнопкам;
- при задании `selectable={true}` в реализации используется тег `"label"`. В остальных случаях используется тег `"div"`.

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

### ActionSheet

| Свойство | Тип | По умолчанию | Описание |
| --- | --- | --- | --- |
| `allowClickPropagation` | `boolean` | `-` | По умолчанию событие `onClick` не всплывает. |
| `autoFocus` | `boolean \| "root"` | `true` | Управление поведением автофокуса при появлении всплывающего окна. При прокидывании `true` фокус будет установлен на первый элемент. При прокидывании `root` фокус будет установлен в корень. |
| `description` | `ReactNode` | `-` | Описание всплывающего окна, под заголовком. |
| `disabled` | `boolean` | `-` | **Deprecated**: Since 7.3.0. Будет удалено в **VKUI v9**. |
| `iosCloseItem` | `ReactNode` | `-` | Только мобильный iOS. |
| `mode` | `"menu" \| "sheet"` | `-` | Режим отображения компонента:  - `sheet` – отображение снизу экрана в виде всплывающего окна, подходит для мобильных устройств - `menu` – отображение в виде всплывающего элемента, относительно якорного элемента. |
| `mount` | `boolean` | `-` | **Deprecated**: Since 7.3.0.  Будет удалено в **VKUI v9**. |
| `onClose` | `((reason: ActionSheetOnCloseReason) => void)` | `-` | Обработчик закрытия всплывающего окна. |
| `**onClosed** \*` | `(options: ActionSheetOnCloseOptions) => void` | `-` | Обработчик закрытия всплывающего окна срабатывающий после завершения анимации закрытия.  > Since 8.0.0 аргумент, переданный в данную функцию, устарел и будет удален в **VKUI v10**. > Для получения причины закрытия всплывающего окна используйте свойство `onClose`. |
| `placement` | `PlacementWithAuto` | `-` | Позиционирование всплывающего окна для десктопа. Компонент выберет наилучшее расположение сам, но можно задать приоритетное направление с помощью этого свойства. |
| `popupOffsetDistance` | `number` | `-` | Отступ, где заданное кол-во единиц равняется пикселям. |
| `restoreFocus` | `boolean \| (() => boolean \| HTMLElement)` | `true` | Управление поведением возврата фокуса при закрытии всплывающего окна. |
| `slotProps` | `{ iosCloseItem?: (Omit<ActionSheetItemProps, "mode" \| "isCancelItem"> & HasRootRef<HTMLElement>); } \| undefined` | `-` | Свойства, которые можно прокинуть внутрь компонента: - `iosCloseItem`: свойства для прокидывания в кнопку отмены на iOS. |
| `timeout` | `number` | `0` | Время в миллисекундах после которого срабатывает автофокус при появлении всплывающего окна. |
| `title` | `ReactNode` | `-` | Заголовок всплывающего окна. |
| `**toggleRef** \*` | `ToggleRef` | `-` | Элемент, рядом с которым вылезает всплывающий элемент на десктопе. Лучше передавать `RefObject` c current. |
| `usePortal` | `boolean \| HTMLElement \| RefObject<HTMLElement \| null> \| null` | `true (использует `document.body` как портал по умолчанию)` | Настройка портала для рендеринга компонента.  `true` - использует `portalRoot` из контекста `AppRoot` (если доступен) или `document.body`; `false` - отключает использование портала; `HTMLElement` - указывает конкретный DOM-элемент для использования в качестве портала; `React.RefObject<HTMLElement \| null>` - ссылка на DOM-элемент для использования в качестве портала; `null` - эквивалентно `false`, отключает использование портала. |

### ActionSheetItem

| Свойство | Тип | По умолчанию | Описание |
| --- | --- | --- | --- |
| `after` | `ReactNode` | `-` | Иконка или другой React-элемент для отображения после основного контента. |
| `autoCloseDisabled` | `boolean` | `false` | По умолчанию нажатие на опцию вызывает переданную в `ActionSheet` функцию `onClose`, данное свойство позволяет отключить такое поведение. |
| `before` | `ReactNode` | `-` | Иконка или другой React-элемент для отображения перед основным контентом. |
| `disabled` | `boolean` | `-` | Блокировка взаимодействия с компонентом. |
| `href` | `string` | `-` | Если указано, элемент будет использоваться как ссылка. |
| `iconChecked` | `ReactNode` | `-` | Иконка для `selectable` режима. |
| `isCancelItem` | `boolean` | `-` | **Deprecated**: Since 8.0.0. Свойство устарело и будет удалено в **VKUI v10**. Используйте компонент `ActionSheetDefaultIosCloseItem` или передайте пропсы через `slotProps.iosCloseItem` в `ActionSheet`. |
| `meta` | `ReactNode` | `-` | Дополнительная информация, отображаемая рядом с основным контентом. |
| `mode` | `"default" \| "destructive" \| "cancel"` | `default` | Свойство, определяющее внешний вид элемента действия.  > Since 8.0.0. Значение `"cancel"` устарело и будет удалено в **VKUI v10**. > Используйте компонент `ActionSheetDefaultIosCloseItem` или передайте пропсы через `slotProps.iosCloseItem` в `ActionSheet`. |
| `multiline` | `boolean` | `false` | Все текстовые элементы при необходимости занимают несколько строк. |
| `onClick` | `MouseEventHandler<HTMLElement>` | `-` | По умолчанию `onClick` будет вызван после завершения анимации скрытия и после вызова `onClose`. Из этого следует, что в объекте события значения полей типа `currentTarget` будут не определены. Если вам нужен объект события именно на момент нажатия, используйте `onImmediateClick`. |
| `onImmediateClick` | `MouseEventHandler<HTMLElement>` | `-` | Обработчик нажатия, вызывающийся непосредственно в момент нажатия (в отличие от `onClick`). |
| `selectable` | `boolean` | `-` | Включает возможность выбрать элемент (отображает радиокнопку). |
| `subtitle` | `ReactNode` | `-` | Слот для подсказки или вспомогательного текста. |
| `target` | `string` | `-` | Атрибут `target` для тега `<a>`. |

