Перейти до вмісту
tatetUI

Modal

Модальне вікно зі стеком шарів, пасткою фокуса й блокуванням прокрутки.

Знизу до sm вікно — bottom sheet, вище — центрований діалог. Це не декор: центроване вікно на телефоні з піднятою клавіатурою просто не вміщається.

Приклад

Шапка й футер однакової висоти (хрестик — того ж розміру, що кнопки футера), тож вікно виглядає симетрично. Кнопки футера мають однакову мінімальну ширину (7rem) і центрований підпис — «Скасувати» й «Зберегти» не різняться на око. У режимі bottom sheet (до sm) вони ділять ширину порівну: дві дії поруч читаються рівноцінними й вціляють під великий палець.

Свайп униз (bottom sheet)

swipe-to-close додає шторці нативний жест: над шапкою з'являється ручка, і вікно можна потягнути вниз — за ручку або за шапку (крім її кнопок і полів). Відпустили далі чверті висоти чи різким кидком — вікно закривається, інакше повертається на місце. Жест діє лише поки вікно bottom sheet (до sm): за шапку центрованого діалогу не тягають. Типово вимкнено — поведінка без пропа не змінилася.

Свайп — явна дія, як хрестик: працює з closable і навіть у persistent вікні. Якщо закриття треба підтвердити («Відкинути зміни?»), керуйте v-model самі — відмовлена шторка повертається на місце, а не висить за краєм.

Вкладені оверлеї

Усі оверлеї бібліотеки ділять один стек шарів. Відкрийте другий рівень і натисніть Escape — закриється лише верхній. Те саме з підказкою чи меню всередині вікна: Escape спершу закриває їх, а вікно з формою — лише наступним натиском.

API

Props

НазваТипТиповоОпис
titlestring""Заголовок. Ігнорується, якщо задано слот `header`.
sizelgsmmdxlfull"lg"Ширина панелі.
panelClassstring""Додаткові класи панелі — коли готових розмірів не вистачає.
roledialogalertdialog"dialog"Роль панелі. `alertdialog` — для підтверджень, що переривають роботу і чекають відповіді (UiConfirmDialog): скрінрідер оголошує їх як попередження, а не як звичайне вікно.
modalIdstring—Стабільний id шару в стеку оверлеїв. Задавати не обов'язково: без нього генерується автоматично.
initialFocusstring—CSS-селектор усередині панелі, якому віддати фокус при відкритті. Типово фокус отримує сама панель, а НЕ перший інпут: на мобільних автофокус в інпуті одразу піднімає клавіатуру і з'їдає пів екрана.
ariaLabelstring—Доступне ім'я діалогу, коли слот `header` не є заголовком. Без нього aria-labelledby вказує на контейнер слота, і якщо там лежить поле вводу — ім'я вікна обчислюється з його ЗНАЧЕННЯ. Діалог пошуку оголошувався як «Діалог: тек» на слові «текст».
ariaDescribedbystring—id елемента з поясненням, що саме відбувається. Потрапляє в `aria-describedby` панелі: коли фокус одразу стрибає на кнопку, без цього скрінрідер оголошує лише заголовок і кнопку, пропускаючи сам текст повідомлення.
modelValuebooleanfalseВідкрито. Використовуйте через `v-model`.
closablebooleantrueПоказувати хрестик і дозволяти закриття через Escape.
closeOnBackdropbooleantrueКлік по затемненому фону закриває вікно. Типово `true` — на відміну від UiDrawer, де типово `false`. Модалка зазвичай інформаційна, і випадкове закриття нічого не коштує; drawer майже завжди містить форму, де це втрата введеного.
persistentbooleanfalseНі Escape, ні клік по фону не закривають — лише явна дія.
noPaddingbooleanfalseПрибрати внутрішні відступи вмісту.
swipeToClosebooleanfalseСвайп униз закриває вікно, поки воно bottom sheet (до `sm`): над шапкою з'являється ручка, тягнути можна за неї й за шапку. Як і хрестик, свайп — явна дія: працює з `closable`, навіть якщо вікно `persistent`. Ширше `sm` вікно центроване, і жест вимкнено.

Події

НазваPayloadОпис
update:modelValue[value: boolean]Зміна стану відкриття. Використовуйте через `v-model`.
close[]{ "Вікно закрито — будь-яким способом": "хрестиком, Escape або кліком по фону." }

Слоти

НазваОпис
defaultВміст вікна.
headerЗамінює заголовок цілком. Тоді `title` не використовується.
footerКнопки дій. Футер не рендериться, якщо слот порожній.

Коли використовувати

Для короткої взаємодії, яка має перервати основний потік: підтвердження, компактна форма, перегляд деталі.

Якщо форма велика або користувач має звірятися зі сторінкою під нею — беріть UiDrawer.

Коли НЕ використовувати

Не кладіть у модалку багатокрокові майстри. Заблокована прокрутка фону плюс обмежена висота панелі роблять довгий вміст незручним саме там, де його найбільше.

Не ставте :closable="false", доки у вікні немає власного шляху виходу. Цей прапорець вимикає всі способи закриття одразу: і хрестик, і Escape, і клік по фону. Разом із пасткою фокуса, яка робить решту сторінки inert, вікно стає глухим кутом — вийти можна хіба перезавантаженням вкладки. Саме так свого часу поводився пошук по цій документації. Якщо закриття справді має бути лише явним, лишіть у вікні власну кнопку, яка змінює v-model.

Доступність

Панель має role="dialog", aria-modal="true" і назву — з title через aria-labelledby або з aria-label, якщо заголовок замінено слотом.

Для підтверджень, що переривають роботу й чекають відповіді, задайте role="alertdialog" і ariaDescribedby — id елемента з текстом питання. Коли фокус одразу стає на кнопку, без опису скрінрідер оголошує лише заголовок і кнопку й мовчить про те, що саме підтверджується. Так робить UiConfirmDialog.

Коли слот header містить не заголовок, а керування — поле пошуку, перемикач — назву треба задати props ariaLabel явно. Інакше aria-labelledby вказує на контейнер слота, і назву вікна браузер обчислює зі значення поля: діалог оголошувався як «Діалог: тек», щойно користувач набирав «текст».

Фокус утримується всередині панелі, а при закритті повертається на елемент, з якого вікно відкрили. Решта прямих дітей <body> на час відкриття позначаються inert і aria-hidden — з лічильником, тож вкладені оверлеї можна закривати в будь-якому порядку: атрибути знімаються, коли елемент відпустив останній оверлей.

Типово фокус отримує сама панель, а не перший інпут: на мобільних автофокус в інпуті одразу піднімає клавіатуру і з'їдає пів екрана. Якщо потрібно інакше — задайте initialFocus.

Портування

Компонент не працює сам по собі: йому потрібні чотири композабли зі списку залежностей вище. Разом вони становлять overlay-ядро, спільне для UiModal, UiDrawer і UiConfirmDialog — копіюйте їх один раз на проєкт.