Navigation
Menubar
A horizontal bar of menus that behaves like one desktop-style menu strip.
When to use it: Use it when an application area offers several persistent groups of commands.
Example
import { Menu, MenuItem, MenuList, MenuPopover, MenuSeparator, MenuTrigger } from "@comp0/react";
import { Menubar } from "@comp0/react";
export function Example() {
return (
<Menubar
aria-label="Notes"
className="flex items-center gap-1 rounded border border-zinc-950/10 p-1 dark:border-white/10"
>
<Menu>
<MenuTrigger className="rounded px-3 py-2.5 text-base text-zinc-800 select-none hover:bg-zinc-100 data-open:bg-zinc-100 sm:py-2 sm:text-sm dark:text-zinc-100 dark:hover:bg-zinc-800 dark:data-open:bg-zinc-800">
File
</MenuTrigger>
<MenuPopover
placement="bottom start"
offset={4}
className="w-44 rounded border-0 bg-white p-1 shadow-lg ring-1 ring-zinc-950/10 dark:bg-zinc-900 dark:shadow-none dark:ring-white/10"
>
<MenuList>
<MenuItem
className="w-full rounded px-3 py-2.5 text-left text-base text-zinc-800 select-none hover:bg-zinc-100 sm:py-2 sm:text-sm dark:text-zinc-100 dark:hover:bg-zinc-800"
value="new"
>
New note
</MenuItem>
<MenuItem
className="w-full rounded px-3 py-2.5 text-left text-base text-zinc-800 select-none hover:bg-zinc-100 sm:py-2 sm:text-sm dark:text-zinc-100 dark:hover:bg-zinc-800"
value="duplicate"
>
Duplicate
</MenuItem>
<MenuSeparator className="my-1 h-px bg-zinc-950/10 dark:bg-white/10" />
<MenuItem
className="w-full rounded px-3 py-2.5 text-left text-base text-zinc-800 select-none hover:bg-zinc-100 sm:py-2 sm:text-sm dark:text-zinc-100 dark:hover:bg-zinc-800"
value="delete"
>
Delete
</MenuItem>
</MenuList>
</MenuPopover>
</Menu>
<Menu>
<MenuTrigger className="rounded px-3 py-2.5 text-base text-zinc-800 select-none hover:bg-zinc-100 data-open:bg-zinc-100 sm:py-2 sm:text-sm dark:text-zinc-100 dark:hover:bg-zinc-800 dark:data-open:bg-zinc-800">
Edit
</MenuTrigger>
<MenuPopover
placement="bottom start"
offset={4}
className="w-44 rounded border-0 bg-white p-1 shadow-lg ring-1 ring-zinc-950/10 dark:bg-zinc-900 dark:shadow-none dark:ring-white/10"
>
<MenuList>
<MenuItem
className="w-full rounded px-3 py-2.5 text-left text-base text-zinc-800 select-none hover:bg-zinc-100 sm:py-2 sm:text-sm dark:text-zinc-100 dark:hover:bg-zinc-800"
value="undo"
>
Undo
</MenuItem>
<MenuItem
className="w-full rounded px-3 py-2.5 text-left text-base text-zinc-800 select-none hover:bg-zinc-100 sm:py-2 sm:text-sm dark:text-zinc-100 dark:hover:bg-zinc-800"
value="redo"
>
Redo
</MenuItem>
</MenuList>
</MenuPopover>
</Menu>
<Menu>
<MenuTrigger className="rounded px-3 py-2.5 text-base text-zinc-800 select-none hover:bg-zinc-100 data-open:bg-zinc-100 sm:py-2 sm:text-sm dark:text-zinc-100 dark:hover:bg-zinc-800 dark:data-open:bg-zinc-800">
View
</MenuTrigger>
<MenuPopover
placement="bottom start"
offset={4}
className="w-44 rounded border-0 bg-white p-1 shadow-lg ring-1 ring-zinc-950/10 dark:bg-zinc-900 dark:shadow-none dark:ring-white/10"
>
<MenuList>
<MenuItem
className="w-full rounded px-3 py-2.5 text-left text-base text-zinc-800 select-none hover:bg-zinc-100 sm:py-2 sm:text-sm dark:text-zinc-100 dark:hover:bg-zinc-800"
value="zoom-in"
>
Zoom in
</MenuItem>
<MenuItem
className="w-full rounded px-3 py-2.5 text-left text-base text-zinc-800 select-none hover:bg-zinc-100 sm:py-2 sm:text-sm dark:text-zinc-100 dark:hover:bg-zinc-800"
value="zoom-out"
>
Zoom out
</MenuItem>
</MenuList>
</MenuPopover>
</Menu>
</Menubar>
);
}Anatomy
Dashed frames are invisible state providers; shaded shapes own real DOM. Numbered pins match the list below.
A wireframe sketch of the assembled component. Each numbered marker matches a part in the list that follows.
Menubar
Horizontal bar of menus that shares one tab stop; while a menu is open, openness follows focus across the bar. Owns a DOM element.
Menu
Open-state provider for one bar item; the same Menu component used standalone. Does not add a DOM element.
MenuTrigger
Inside a Menubar it renders as the bar's menuitem and joins the roving tab stop. Owns a DOM element.
MenuPopover
Floating surface opened below its bar item. Owns a DOM element.
MenuListOptional
Menu collection inside the surface. Owns a DOM element.
MenuSeparatorOptional
Rule between groups of items. Owns a DOM element.
MenuItem
Action item. Owns a DOM element.
Step by step
- 1
Add the main part
Wrap your Menu components in Menubar and give the bar an aria-label.
- 2
Add the supporting parts
Each Menu keeps its usual MenuTrigger, MenuPopover, and MenuList; the trigger becomes the bar's menuitem automatically.
- 3
Make the behavior clear
Arrow keys rove the bar with one tab stop, and once a menu is open the openness follows focus to its neighbors.
Exampletsx <Menubar aria-label="Notes"><Menu><MenuTrigger>File</MenuTrigger><MenuPopover><MenuList><MenuItem>New note</MenuItem></MenuList></MenuPopover></Menu></Menubar>
Keyboard
- ⇥
- Moves into the bar to the last-used item; Tab again leaves.
- →
- Moves to the next item, wrapping; while a menu is open, opens the neighbor's menu.
- ←
- Moves to the previous item, wrapping; while a menu is open, opens the neighbor's menu.
- ↓
- Opens the focused item's menu and focuses the first item.
- ↵
- Opens the focused item's menu and focuses the first item.
- Space
- Opens the focused item's menu and focuses the first item.
- Home
- Moves to the first item.
- End
- Moves to the last item.
- Esc
- Closes the open menu and returns focus to its bar item. · open menu
- →
- Opens the focused submenu item. · submenu
- ←
- Closes the submenu and refocuses its item. · submenu
Forms and accessibility
No native form behavior.
Accessibility checklist
- Give the menubar an aria-label naming the area it commands, such as Notes.
- Keep the bar for persistent application commands; a row of unrelated buttons should be a toolbar instead.
- Keep bar items in a visual order that matches the arrow-key order.
API reference
import { Menu, MenuItem, MenuList, MenuPopover, MenuSeparator, MenuTrigger, Menubar } from "@comp0/react";Menubar
DOM elementHorizontal bar of menus that shares one tab stop; while a menu is open, openness follows focus across the bar.
| Prop | Type | Description |
|---|---|---|
aria-label | string | Names the bar after the application area it commands, such as Notes. |
Menu
Context onlyOpen-state provider for one bar item; the same Menu component used standalone.
| Prop | Type | Description |
|---|---|---|
open / defaultOpen | boolean | Controlled or initial open state. |
onToggle | (open: boolean) => void | Receives the next open state. |
MenuTrigger
DOM elementInside a Menubar it renders as the bar's menuitem and joins the roving tab stop.
| Prop | Type | Description |
|---|---|---|
disabled | boolean | Disables opening and skips the item when arrowing. |
MenuPopover
DOM elementFloating surface opened below its bar item.
| Prop | Type | Description |
|---|---|---|
placement | PopoverPlacement | Trigger side to open on, usually "bottom start"; flips when there is no room. |
offset | number | Pixel gap between the bar item and the menu. |
MenuList
OptionalDOM elementMenu collection inside the surface.
MenuSeparator
OptionalDOM elementRule between groups of items.
MenuItem
DOM elementAction item.
| Prop | Type | Description |
|---|---|---|
onClick | (event) => void | Runs the action; preventDefault keeps the menu open. |
value | string | Optional identity for typeahead and data-value. |
disabled | boolean | Disables the action. |
Style hooks
Attributes that appear while a state is true. Target them with Tailwind data variants such as data-open:bg-zinc-100, or with any CSS selector.
[data-open]on MenuTrigger, MenuPopover
- That menu is open.
:popover-openon MenuPopover
- Native pseudo-class equivalent.
:focus-visibleon MenuTrigger, MenuItem
- The item has visible keyboard focus.
[data-disabled]on MenuTrigger, MenuItem
- The item is disabled.