ModalPage
Компонент реализующий модальное окно. Позволяет показать дополнительный контент, удерживая пользователя в текущем контексте страницы/приложения.
Область применения
- Формы для редактирования.
- Детали профиля пользователя.
- Разделы настроек, которые должны удерживать пользователя в текущем контексте приложения.
Анатомия
ModalPage
состоит из композиции нескольких компонентов.
Опциональные компоненты, передающиеся пользователем:
- ModalPageHeader – передаётся через параметр
header
; ModalPageFooter
– передаётся через параметрfooter
.
Обязательные компоненты, задающиеся библиотекой:
ModalOutlet
– обёртка с фиксированной позицией для перекрытия других элементов в DOM;ModalOverlay
– интерактивный задний фон;ModalPageInternal
– инкапсулирует в себе всю логику поведения;ModalPageContent
– оборачивает переданныйchildren
в CustomScrollView.
Поведение
Параметр open
задает состояние показа/скрытия ModalPage
. По умолчанию компонент скрыт.
При состоянии open={false}
компонент размонтируется из DOM. Чтобы отключить это поведение, необходимо задать параметр
keepMounted
.
Смена состояния сопровождается анимацией содержимого ModalPage
, а также ModalOverlay
. За сменой состояния можно следить
через события:
onOpen
onOpened
onClose
– передаёт в аргумент причину закрытия (см. описание в таблице с API)onClosed
Отличие onOpened
/onClosed
от onOpen
/onClose
в том, что они вызываются после завершения анимации.
Далее поведение зависит от разрешения экрана.
Настольный режим
При разрешении >= 768px
компонент ModalPage
имеет вид диалогового окна.
При open={true}
:
- параметр
size
будет ограничивать максимальную ширину окна; - навигация через
Tab
иShift
+Tab
будет зациклена на содержимомModalPage
.
По умолчанию, пользователь может закрыть диалоговое окно с помощью:
- нажатия на кнопку закрытия, что вызовет событие
onClose
с аргументомclick-close-button
; - нажатия на
ModalOverlay
, что вызовет событиеonClose
с аргументомclick-overlay
; - нажатия на
Esc
, что вызовет событиеonClose
с аргументомescape-key
.
Мобильный режим
При разрешении <= 767px
компонент ModalPage
имеет вид панели, выдвигающейся снизу вверх (далее bottom sheet).
При open={true}
навигация через Tab
и Shift
+ Tab
будет зациклена на содержимом ModalPage
(допустимо, т.к. к устройству
может быть подключена клавиатура).
По умолчанию, пользователь может закрыть bottom sheet с помощью:
- нажатия на
ModalOverlay
, что вызовет событиеonClose
с аргументомclick-overlay
; - нажатия на
Esc
, что вызовет событиеonClose
с аргументомescape-key
(допустимо, т.к. к устройству может быть подключена клавиатура); - определенного взаимодействие через тач или указатель мыши, что вызовет событие
onClose
с аргументомswipe-down
(см. Взаимодействие через тач или указатель мыши)
Взаимодействие через тач или указатель мыши
Для bottom sheet можно задавать на какой процент высоты экрана изначально должна открываться панель – этот процент задаётся
через параметр settlingHeight
. Минимальное значение 25
, а максимальное 100
. По умолчанию используется 50
.
От settlingHeight
зависит дальнейшее поведение bottom sheet:
- при
settlingHeight <= 90
у bottom sheet появляется возможность через перетаскивание раскрывать высоту до100
и схлопывать обратно до переданногоsettlingHeight
; - при
settlingHeight > 90
значение приводится к100
и, соответственно, bottom sheet всегда раскрывается на100
.
Если необходимо, чтобы высота bottom sheet зависела от его контента, то стоит использовать параметр dynamicContentHeight
,
вместо settlingHeight
.
В обеих случаях перетаскивание bottom sheet изменяет прозрачность ModalOverlay
– при перетаскивание вниз фон становится
светлее. При settlingHeight
процент прозрачности высчитывается относительно переданного значения в settlingHeight
.
Пользователь через перетаскивание может вызвать закрытие bottom sheet по следующим условиям:
-
onClose('swipe-down')
вызовется сразу же, если bottom sheet достиг высоты0
, независимо закончил ли пользователь взаимодействие с ним или нет; -
onClose('swipe-down')
вызовется, если после окончания взаимодействия с bottom sheet его высота будет:- при
settlingHeight
: меньше половины переданного значения вsettlingHeight
(пример, еслиsettlingHeight={50}
, то условием закрытие будетheight < 50 / 2
); - при
dynamicContentHeight
: меньше половины контента;
- при
-
onClose('swipe-down')
вызовется при сильном смахивании вниз;- при
settlingHeight
: добавляется условии, что bottom sheet должен находится на высоте равной переданному вsettlingHeight
;
- при
При следующих условиях возможность перетаскивания замораживается, чтобы не блокировать пользователя:
- при условии
disableContentPanningGesture={false}
, есть взаимодействие с контентомModalPageContent
приscrollTop !== 0
; - есть взаимодействие с горизонтальным скроллом;
- есть взаимодействие с текстовым полем;
- есть взаимодействие с выделенным текстом;
- есть взаимодействие с элементом вызвавшим
event.stopPropagation()
наonTouchStart
илиonMouseDown
. - есть взаимодействие с элементом с data-атрибутом
data-vkui-block-sheet-behavior
(в частности, используется приdisableContentPanningGesture={true}
);
Доступность (a11y)
ModalPage
является модальным окном (role="dialog"
), а значит у него обязательно должно быть имя — его краткое название. Благодаря этому пользователи вспомогательных технологий знают, что это за элемент и какое у него содержимое.
Задать имя можно с помощью следующих способов:
- используя свойство
title
; - используя свойство
aria-label
; - используя свойство
aria-labelledby
; - используя внутри компонент ModalPageHeader. Этот компонент сам свяжется с
ModalPage
через контекст c помощьюaria-labelledby
.
FAQ
Как поменять максимальную ширину контента?
Используйте параметр size
.
Как задать фиксированную высоту контента?
Используйте параметр height
. Высоту можно задать как числом (height={300}
) так и в процентах (height={'80%'}
).
Как правильно применять параметр autoFocus
?
К сожалению, из-за особенностей React, autoFocus
ломает CSS анимацию.
Чтобы исправить проблему, следует отказаться от autoFocus
и выставлять фокус вручную при событии onOpened
.
Свойства и методы
Свойство | Описание |
---|---|
disableContentPanningGesture | boolean Отключает раскрытие и закрытие панели в мобильном виде. По умолчанию: - |
disableFocusTrap | boolean Позволяет отключить захват фокуса. Нужно использовать, когда поверх одной модалки открывается другая, чтобы два По умолчанию: - |
dynamicContentHeight | boolean Если высота контента в модальной странице может поменяться, нужно установить это свойство. По умолчанию: - |
footer | ReactNode Подвал модальной страницы, По умолчанию: - |
getModalContentRef | Ref<HTMLDivElement> Возвращает DOM-элемент содержимого модального окна. По умолчанию: - |
getRootRef | Ref<HTMLDivElement> По умолчанию: - |
header | ReactNode Шапка модальной страницы, По умолчанию: - |
height | string | number Задаёт модальному окну фиксированную высоту. Можно передать числовое значение в пикселях, а можно строкой, в том числе и в процентах “50%”. В мобильной версии ‘settlingHeight’ будет считаться относительно заданного height. По умолчанию: - |
hideCloseButton | boolean Скрывает кнопку закрытия (актуально для iOS, так как можно отрисовать кнопку закрытия внутри модалки). По умолчанию: - |
id | string По умолчанию: - |
keepMounted | boolean Сохранять ли компонент в DOM при По умолчанию: false |
modalContentTestId | string
По умолчанию: - |
modalDismissButtonLabel | string Текст для скринридера. По умолчанию: - |
modalDismissButtonTestId | string
По умолчанию: - |
modalOverlayTestId | string
По умолчанию: - |
nav | string Уникальный идентификатор навигационного элемента (вместо id) По умолчанию: - |
noFocusToDialog | boolean Отключает фокус на интерактивный элемент после открытия модалки. По умолчанию: - |
onClose | ((reason: ModalPageCloseReason, event?: UIEvent<HTMLElement, UIEvent>) => void) | undefined Будет вызвано при начале закрытия модалки. По умолчанию: - |
onClosed | VoidFunction Будет вызвано при окончательном закрытии модалки. По умолчанию: - |
onOpen | VoidFunction Будет вызвано при начале открытия модалки. По умолчанию: - |
onOpened | VoidFunction Будет вызвано при окончательном открытии модалки. По умолчанию: - |
open | boolean Состояние видимости. По умолчанию: false |
outsideButtons | ReactNode Управляющие элементы под кнопкой закрытия. Доступно только в По умолчанию: - |
preventClose | boolean Позволяет отключить возможность закрытия модальной страницы (смахивание, клавиша ⚠️ ВНИМАНИЕ: использование этой опции негативно сказывается на пользовательском опыте. По умолчанию: - |
restoreFocus | boolean | (() => boolean | HTMLElement) По умолчанию: true |
settlingHeight | number Процент, на который изначально будет открыта модальная страница. Игнорируется при включении По умолчанию: 50 |
size | number | "s" | "m" | "l" Задаёт контенту максимальную ширину на десктопе. По умолчанию: s |
style | Omit<CSSProperties, "height" | "maxHeight" | "maxWidth"> Дополнительные стили. По умолчанию: - |