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

Menu

Випадне меню, телепортоване в body, з фліпом і притисканням до вікна.

Меню телепортується в body, а не рендериться в потоці. Це не оптимізація: всередині контейнера з overflow: hidden або overflow-x: auto — а це будь-яка таблиця — випадайка в потоці була б обрізана краєм контейнера.

Приклад

Обрано: —

API

Props

НазваТипТиповоОпис
placementbottom-endbottom-startbottomtopright"bottom-end"Куди відкривати відносно тригера. Автоматично фліпається, якщо не влазить.
panelRolemenudialognone"menu"Семантика панелі: menu для команд, dialog для складених контролів.
ariaLabelstringundefinedДоступна назва панелі, особливо для `panelRole="dialog"`.
widthstringШирина панелі, напр. `"14rem"`. Без неї — за вмістом.
disabledboolean

Події

НазваPayloadОпис
update:open[value: boolean]Меню відкрито або закрито.

Слоти

НазваОпис
triggerТригер. `triggerAttrs` потрібно передати реальній кнопці через `v-bind`.
contentВміст панелі. `toggle` дає змогу закрити меню з пункту.

Доступно через ref

НазваТипОпис
open() => Promise<void>Відкрити меню програмно.
close(restoreFocus?: boolean) => voidЗакрити меню програмно.

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

Для набору дій над однією сутністю, які не варті окремих кнопок: перейменувати, дублювати, експортувати, видалити.

Тригер малюєте самі через слот — компонент не нав'язує вигляду кнопки. Передайте triggerAttrs реальній кнопці через v-bind, щоб ARIA-стан належав фокусованому елементу, а не wrapper-у.

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

Не робіть меню з вибором значення. Для цього є UiSelect — він має role="combobox", працює з клавіатури і повідомляє обране значення.

Не ховайте в меню головну дію екрана. Те, що потрібно всім, має бути кнопкою.

Доступність

Тригер отримує aria-haspopup і aria-expanded через triggerAttrs, панель — role="menu". Пунктам додавайте role="menuitem" самі: компонент не знає, чим ви їх наповните.

Стрілки, Home та End переміщують фокус між пунктами. Для складеного вмісту на кшталт налаштувань таблиці використовуйте panelRole="dialog" і ariaLabel, а не прикидайте форму меню-командою.

Після закриття фокус повертається на тригер. Без цього Tab починав би обхід з початку сторінки, і користувач втрачав би місце.

Escape викликає stopPropagation — інакше той самий натиск закрив би ще й модалку, у якій меню стоїть.

Деталі реалізації

Позиція рахується власним кодом, без @floating-ui — компонент має копіюватись у чужий проєкт без нової залежності.

Вимірювання відбувається двічі: перший раз із запасними габаритами (панелі ще немає в DOM), другий — коли вона їх отримала. Без другого проходу вибір напрямку відкриття інколи помилявся.

Слухач прокрутки навішено з capture: true. Подія scroll не спливає, тож без цього відкрита панель лишалася б висіти на місці, поки контейнер під нею від'їжджає.

Базовий z-index панелі — 1100; усередині глибоко вкладеного оверлея він автоматично піднімається над шаром найближчого Modal або Drawer.