Purpose
Expose primary categories that open nested menus or dialogs.
Loading ...
menubarA persistent horizontal menu of top-level choices that usually opens submenus. Think application menu bars (“File”, “Edit”, “View”).
Top-level menubar with nested menus, horizontal navigation, and Esc to close.
Expose primary categories that open nested menus or dialogs.
Contains menuitem elements that may own role="menu" submenus.
Announced as “menubar”. Users expect left/right arrows to move between top-level items.
Complex web apps mimicking desktop software (design tools, IDEs).
Sites needing strongly categorized command groups.
Expose keyboard shortcuts and provide a predictable structure for advanced users.
role="menubar" should include aria-label (e.g., “Editor commands”).
Top-level items use role="menuitem" and usually have tabindex="0" / -1 for roving focus.
Use role="menu" for dropdown panes. Connect via aria-controls/aria-haspopup on the triggering menuitem.
| Action | Keys | Result |
|---|---|---|
| Move between top-level items | ArrowLeft / ArrowRight | Cycles focus through the menubar. |
| Open submenu | ArrowDown / Enter / Space | Opens the submenu owned by the focused item. |
| Close submenu | Escape / ArrowUp | Closes submenu and returns focus to menubar item. |
| Jump to first/last item | Home / End | Moves focus to the first or last menubar item. |
| Mnemonic letters | Character keys | Moves focus to the next item whose label starts with the typed letter. |
aria-orientationOptionalMenubars are typically horizontal. Set explicitly to avoid ambiguity.
aria-haspopupOptionalMenuitems that open submenus must use aria-haspopup="menu" and manage aria-expanded.
aria-controlsOptionalLink menubar items to their submenu containers for assistive tech navigation.
aria-expandedOptionalReflect whether its submenu is visible. Update as soon as menus open or close.
Allow Alt + first letter or other accelerators if your user base expects them.
Keep the menubar visible at all times and ensure focus remains within the menu system when open.
Support wrapping navigation so Right from the last item returns to the first and vice versa.
When the page loses focus, close any open submenus to avoid stranded popups.
Each menuitem toggles aria-expanded when a submenu is available.
<nav role="menubar" aria-label="Editor commands">
<button role="menuitem" aria-haspopup="menu" aria-controls="file-menu" aria-expanded="false">File</button>
<button role="menuitem" aria-haspopup="menu" aria-controls="edit-menu" aria-expanded="false">Edit</button>
<button role="menuitem" aria-haspopup="menu" aria-controls="view-menu" aria-expanded="false">View</button>
</nav>Simple logic to move focus between items.
const menubar = document.querySelector('[role="menubar"]')
const items = Array.from(menubar.querySelectorAll('[role="menuitem"]'))
let activeIndex = 0
function updateFocus(index) {
items[activeIndex].tabIndex = -1
activeIndex = index
items[activeIndex].tabIndex = 0
items[activeIndex].focus()
}
items.forEach((item, index) => {
item.tabIndex = index === 0 ? 0 : -1
})
menubar.addEventListener('keydown', (event) => {
if (event.key === 'ArrowRight') {
event.preventDefault()
updateFocus((activeIndex + 1) % items.length)
} else if (event.key === 'ArrowLeft') {
event.preventDefault()
updateFocus((activeIndex - 1 + items.length) % items.length)
}
})Wrap navigation seamlessly so users never get trapped at the ends.
Include accelerators in labels (“Save ⌘S”) to help power users.
Support tap/long-press for touch screens without breaking keyboard logic.
Anchors that navigate away instead of opening menus break the menubar paradigm.
Use buttons for menuitems and open submenus in-place.
Each menubar item often owns a menu.
Learn moreActionable descendant of menubar.
Learn moreExclusive options inside menus.
Learn more