Тег <menuitem> (от английского menu item, «пункт меню») задумывали как один пункт контекстного меню: пользователь нажимает правой кнопкой мыши, и браузер показывает меню, которое собрал автор страницы. Пункты записывали внутри <menu type="context">. Закрывающий тег </menuitem> нужен: без него следующий пункт вложится в предыдущий.
Идею из стандарта HTML убрали. По умолчанию такое меню показывал только Firefox, да и тот отключил. Сегодня menuitem для них неизвестный тег: нарисовать меню он не может. Новые страницы с ним писать не нужно, меню собирают из menu, button и атрибута popover.
<menu type="context" id="ctx">
<menuitem label="Копировать"></menuitem>
<menuitem label="Вырезать"></menuitem>
</menu>
<div contextmenu="ctx">Правый щелчок здесь</div>
В этой статье
Тег menuitem в HTML: что это и для чего создавали
Раньше контекстное меню страницы, то есть меню по правому щелчку, нельзя было собрать на чистом HTML: приходилось писать скрипты. Для этого придумали пару из menu и menuitem. Меню связывали с любым тегом атрибутом contextmenu, а пункты описывали в menuitem.
У menuitem были свои атрибуты. В таблице они перечислены по описанию из старой спецификации, браузер их сегодня не читает.
| Атрибут | Что делал |
|---|---|
label | название пункта меню, показывалось в меню |
type | вид пункта: command, checkbox или radio; нужен для флажков и переключателей |
icon | адрес картинки рядом с названием |
disabled | пункт нельзя выбрать |
checked | отмеченное состояние флажка или переключателя |
radiogroup | название группы переключателей для type="radio" |
default | пункт по умолчанию |
Родителем пункта служил menu type="context". Сам menu остался в HTML как список команд, а вот его тип context и теги пунктов из стандарта убрали.
Как записывать menuitem: закрывающий тег нужен
В старой спецификации menuitem считался пустым тегом, но браузеры так его не разбирали. Сегодня это неизвестный тег, а у такого закрывающий нужен. Если закрывающий </menuitem> не записать, каждый следующий пункт попадёт внутрь предыдущего: у menu останется один дочерний тег, а остальные вложатся друг в друга.
<menu>
<menuitem label="A">
<menuitem label="B">
<menuitem label="C">
</menu>
Пример: как браузер разбирает menuitem
Кнопки меняют запись. Под ней показаны число дочерних тегов у menu и глубина последнего пункта.
Работает ли menuitem сейчас
Нет. Браузер создаёт для menuitem неизвестный элемент: класса HTMLMenuItemElement в нём нет, а у тега нет ни свойства label, ни других свойств пункта. По умолчанию display у него inline. Название из label не рисуется, а текст внутри показывается как обычный строчный.
Атрибут contextmenu тоже не работает: у тегов нет свойства contextMenu, а правый щелчок открывает обычное меню браузера. Тег menu с type="context" остаётся простым блоком и ничего не показывает.
console.log(typeof HTMLMenuItemElement);
console.log("contextMenu" in HTMLElement.prototype);
Пример: что делает браузер с menuitem
Кнопки меняют запись. Вердикты считаются по классу тега, размеру и свойствам.
Какие браузеры понимают menuitem
Данные взяты из таблицы совместимости caniuse: там тег отмечен как удалённый из стандарта HTML.
Пример: таблица версий
| Браузер | Когда понимал | Заметка |
|---|---|---|
| Chrome | нет | версии 41-60 понимали тег только за флагом, отключённым по умолчанию; с версии 61 нет совсем |
| Edge | нет | ни в одной версии |
| Firefox | 8-84 | понимал частично; с версии 85 отключён по умолчанию |
| Safari | нет | ни в одной версии |
Чем заменить menuitem: menu с button и popover
Меню собирают из обычных тегов. Простейший вариант: menu со списком li, а в каждом пункте button. Кнопки получают фокус с клавиатуры, поэтому отдельный скрипт для доступности не нужен.
<menu>
<li><button type="button">Копировать</button></li>
<li><button type="button">Вырезать</button></li>
</menu>
Чтобы меню открывалось как всплывающее, добавляют атрибут popover и кнопку с popovertarget. Браузер сам показывает и скрывает такой блок поверх страницы, а в CSS его состояние описывает псевдокласс :popover-open.
<button type="button" popovertarget="pp">Меню</button>
<div id="pp" popover>
<menu>
<li><button type="button">Копировать</button></li>
<li><button type="button">Вырезать</button></li>
</menu>
</div>
Контекстное меню по правому щелчку собирают скриптом: слушают событие contextmenu, отменяют меню браузера и открывают свой блок с popover методом showPopover().
area.addEventListener("contextmenu", (e) => {
e.preventDefault();
menu.showPopover();
});
Пример: меню без menuitem
Кнопки переключают вариант: список кнопок и всплывающее меню. Состояние popover читается из страницы после каждого нажатия.
Частые ошибки с тегом menuitem
Почти все ошибки с menuitem от ожидания, что браузер покажет меню.
| Ошибка | Что получится | Как исправить |
|---|---|---|
menuitem без закрывающего тега | Следующие пункты вкладываются друг в друга, у menu один дочерний тег | Закрывать каждый menuitem |
menu type="context" с атрибутом contextmenu | Меню не появится, правый щелчок открывает обычное меню браузера | Событие contextmenu и блок с popover |
Название пункта только в label | Ничего не рисуется, размер 0 на 0 | button внутри li |
menuitem type="checkbox" или type="radio" | Флажка и переключателя нет | input type="checkbox" или type="radio" |
menuitem в новых страницах | Валидатор HTML показывает ошибку: тег устарел | menu с button или popover |