角色 控件
menuitem
将元素标记为菜单或菜单栏内的可操作项。没有对应的 HTML 原生元素——菜单是仅靠 ARIA 实现的构件。仅在构建真正的应用程序式菜单时使用此角色;普通导航列表不应使用 menu/menuitem。
何时使用
仅在 role="menu" 或 role="menubar" 内部使用,且仅当该菜单是应用程序菜单时——即模仿桌面应用文件/编辑/视图菜单栏的那种菜单,具备单 Tab 停靠点、方向键导航和 Esc 关闭功能。
网站的顶部导航不是菜单。应使用带 <ul> 链接列表的 <nav>。将两者混淆是 Web 上最常见的 ARIA 错误——它会让键盘用户陷入方向键导航,而 Tab 键才是更自然的方式;同时它会告诉屏幕阅读器”应用程序菜单”,而内容实际上只是链接。
兄弟角色:menuitemcheckbox(用于可切换的菜单项)和 menuitemradio(用于菜单内的单选项)。
键盘与焦点契约
参照 APG 菜单模式:
- Tab 键进入和退出菜单——进入时焦点落在第一个 menuitem 上。Tab 键不会在各项之间循环。
- 上/下方向键在各项之间移动焦点(含循环回绕)。
- 右/左方向键打开子菜单/返回父菜单。
- Enter 或 Space 激活当前获焦项。
- Escape 关闭菜单并将焦点返回触发元素。
- 输入字母可跳转到以该字母开头的下一项(预输入)。
使用漫游 tabindex:只有当前获焦的 menuitem 设置 tabindex="0",其余项设置 tabindex="-1"。
常见错误
- 对网站导航中的普通链接使用
role="menuitem"。会造成键盘陷阱和屏幕阅读器的错误播报。 - 每个 menuitem 都设置
tabindex="0",导致 Tab 键逐项步进。正确模式是单 Tab 停靠点。 - 子菜单仅在鼠标悬停时打开,右方向键无法触发。
- Escape 关闭子菜单后焦点丢失,用户被遗留在菜单之外。
- 项目缺少无障碍名称,因为图标是唯一内容——请添加
aria-label。
示例
<button id="fileBtn" aria-haspopup="menu" aria-expanded="false" aria-controls="fileMenu">
文件
</button>
<ul id="fileMenu" role="menu" aria-labelledby="fileBtn" hidden>
<li role="menuitem" tabindex="0">新建</li>
<li role="menuitem" tabindex="-1">打开</li>
<li role="menuitem" tabindex="-1" aria-haspopup="menu" aria-expanded="false">
打开最近
</li>
<li role="separator"></li>
<li role="menuitem" tabindex="-1">保存</li>
</ul>