# Menu

> Commands and options, opened from a control or at what they are about, and closed once a choice is made.

A menu presents a list of commands or options, opened from a control — or, as a
context menu, at the thing it is about — and closed once a choice is made. It
keeps commands out of the way until they are wanted.

## When to use

Use a menu for commands that act on the current context, and for options people
change occasionally. Commands used constantly deserve their own controls. When
people choose among visible options as part of a task, a
[listbox](https://ui.publictheta.com/components/listbox.md) keeps the choice in view.

Use a context menu for the commands that apply to what is under the pointer: an
item of a list, a selection, a region. It is a shortcut and never the only way:
everything in it is also reachable from a control that can be seen, since nothing
on the screen says a context menu is there.

## Best practices

**Name items for what they do.** Begin with a verb for a command ("Duplicate",
"Move to Trash") and with the noun for an option ("Ruler"). Keep labels short,
and begin them with the word that distinguishes them, since people scan the
start and typeahead matches it.

**Group related items** with separators, and give a group a heading when its
items are a set of choices, such as a sort order.

**Show state with a checkmark.** An option that is on or off shows a checkmark
when it is on. Options of which exactly one applies form a group, with a mark
beside the current one.

**Start every label at the same edge.** When any item of a menu can be checked,
every item of that menu leaves room for the mark, so that the labels form one
column. A submenu is its own menu, and is judged by its own items.

**Disable rather than hide** an item that cannot be used at the moment, so the
menu's shape stays familiar and people can learn where things are.

**Mark items that need more.** An item that opens a submenu shows an arrow; an
item that leads to a dialog ends its label with an ellipsis ("Find…").

**Show the shortcut, in the platform's own writing.** A command that has a
keyboard shortcut shows it after its label, where people learn it: ⇧⌘N where the
command key is ⌘, Ctrl+Shift+N elsewhere, from one statement of the shortcut. It
is told to assistive technology as the item's shortcut, once, and is not part of
the item's name. Where there is no keyboard — a phone — it is not shown.

**Make an item that leads somewhere a link.** An item that opens a page is a
real link, so that it can be opened in a new tab, copied or dragged like any
other. Choosing it — by click, by key, or by dragging to it — follows the link
and closes the menu.

**Keep submenus shallow.** One level of submenu is easy to use; more than one
makes commands hard to find and hard to reach.

**Close the menu when a choice is made**, and return focus to the control that
opened it — or, for a context menu, to what had focus before it opened.

**Close it when attention goes elsewhere.** A menu does not outlast its window's
focus, or a change in the window's size: like a platform's own, it closes.

**Forgive the pointer's path.** A pointer on its way to an open submenu crosses
the items between. While it is heading for the submenu they do not take over;
if it stops on one, they do.

**Act once.** A key held down opens the menu and goes no further; it does not
choose the item the menu opened on. An arrow key held down runs to the last item
and stops there; only a fresh press comes round to the first. A menu that is
fading away takes no presses, so one choice cannot be made twice.

**Let a long menu scroll.** A menu taller than the view stays within it and
scrolls, keeping the item the keys move to in sight. A submenu of a scrolled
menu still opens beside its own item.

**Let what is under a context menu be selected first.** A secondary press on an
item of a list that is not in the selection selects it, and then the menu opens:
the menu is always about what is seen to be selected. A second request elsewhere
moves the menu there, having selected what is there.

**A part held to be dragged asks for no menu.** A finger put down on a handle
or a grip rests there before it moves; that rest is the start of a drag, not a
request. Such a part opens no context menu, however long it is held, and the
drag that follows goes on. (Here it is marked `data-drag-handle`.)

**Give way to the browser's menu only when yours opens.** Where a context menu
is not offered — the region is disabled, the request was declined — the
browser's own menu appears as usual.

## Interaction

| Intent                  | Pointer                                                         | Keyboard                     | Touch                                |
| ----------------------- | --------------------------------------------------------------- | ---------------------------- | ------------------------------------ |
| Open                    | Press the control                                               | Enter, Space or Down Arrow   | Tap the control                      |
| Open at the last item   | —                                                               | Up Arrow                     | —                                    |
| Open a context menu     | Secondary click; Control-click on a Mac                         | Menu key, or Shift+F10       | Touch and hold                       |
| Move between items      | Move the pointer                                                | Up and Down Arrow, Home, End | —                                    |
| Move to an item by name | —                                                               | Type its first letters       | —                                    |
| Choose                  | Click, or release after dragging from the control               | Enter or Space               | Tap                                  |
| Open a submenu          | Rest the pointer on its item                                    | Right Arrow, Enter or Space  | Tap its item                         |
| Close a submenu         | Move to another item                                            | Left Arrow or Escape         | Tap Back                             |
| Close without choosing  | Click outside, press the control again, or drag off and release | Escape; Tab also moves on    | Tap outside, or swipe the sheet down |

Up and Down Arrow wrap from the last item to the first and back, since a menu is
short. In right-to-left text, Left and Right Arrow are mirrored. Space chooses
an item, except while a name is being typed, when it is part of the name. A
press outside closes the menu and does nothing to what it lands on.

Pressing the control and dragging to an item, then releasing, chooses the item
in one gesture. A click — press and release on the control — opens the menu and
leaves it open. Pressing the control, dragging away and releasing outside the
menu closes it: a drag that chose nothing.

A context menu opened with a pointer opens at the pointer with no item
highlighted. Asked for from the keyboard, it opens against what has focus, on
its first item.

## Platform considerations

**Pointer and keyboard.** The menu opens beneath its control, and submenus open
beside their items. A context menu opens from the pointer toward the end of the
line and downward, and to the other side where there is no room; in
right-to-left text it opens the other way.

**Touch.** Items are at least 44 CSS pixels tall. On a phone the menu rises from
the bottom edge as a sheet, across the full width. A submenu does not rise as a
second sheet: it takes the place of its menu in the same sheet, under the one
scrim, beneath a heading that says which submenu it is, with a way back as its
first item. Nothing is highlighted for a finger. Touching and holding opens a
context menu; where a browser reports no such gesture, the hold is timed, with a
little tolerance for a finger that is not quite still, and the platform's own
callout is kept from appearing over the menu.

**Assistive technology.** The control states that it opens a menu and whether it
is open; the menu is named by the control, and a context menu, having none, in
words; items are menu items, checkbox items or radio items with their checked
state; an item that opens a submenu says so; an item with a shortcut states it.
An item answers being activated by assistive technology, which presses nothing.
A context menu answers the request a screen reader makes for one.

See also [Overlays](https://ui.publictheta.com/foundations/overlay.md), [Keyboard navigation](https://ui.publictheta.com/foundations/navigation.md)
and [Typeahead](https://ui.publictheta.com/foundations/typeahead.md).

## Behaviour

Each statement is verified by a test in Chromium, Chromium (touch), Firefox, WebKit, WebKit (touch), unless it names the environments it applies to or is marked open.

### Semantics

- The control states that it opens a menu, and whether it is open.
- The menu is named by the control that opens it.
- Checkbox and radio items state whether they are checked.
- An item that opens a submenu says so, and whether it is open.
- Has no accessibility violations when open.

### Opening

- A click opens the menu, with no item highlighted.
- Pressing the control and releasing it leaves the menu open.
- Enter or Space opens the menu on its first item.
- ArrowDown opens on the first item, ArrowUp on the last.
- Pressing the control, dragging to an item and releasing chooses it.
- Pressing the control, dragging away and releasing outside the menu closes it. *(Chromium, Firefox, WebKit)*

### Keyboard navigation

- An arrow key held down stops at the end: only a fresh press comes round.
- Arrow keys move through the items, wrapping at either end.
- Disabled items are passed over.
- Home and End move to the first and last item.
- Typing moves to the item that starts with what was typed.
- A space is part of a word being typed, and chooses nothing.
- The pointer moves the highlight with it.

### Choosing

- Enter chooses the item, closes the menu and returns focus to its control.
- A click chooses the item and closes the menu.
- Space chooses the item too.
- A key held down chooses nothing: the menu it opened stays open.
- A click that no press came before, as assistive technology makes, chooses the item.
- A disabled item cannot be chosen.
- Choosing a checkbox item turns it on or off.
- Choosing a radio item selects it and deselects the others in its group.

### Dismissal

- Escape closes the menu and returns focus to its control.
- Tab closes the menu and moves on from its control.
- A press outside closes the menu, and does nothing to what it lands on.
- Pressing the control again closes the menu.
- The menu closes when its window loses the person's attention.
- The menu closes when its window changes size. *(Chromium, Firefox, WebKit)*
- A menu that is fading away takes no presses: an item cannot be chosen twice.

### Submenus

- The arrow toward the submenu opens it on its first item.
- Enter and Space open the submenu too.
- The arrow away from it closes the submenu and returns to its item.
- In right-to-left text, the arrows are mirrored.
- Escape closes only the submenu.
- Choosing in a submenu closes every menu and returns focus to the first control.
- Resting the pointer on the item opens its submenu.
- Moving the pointer to another item closes the submenu. *(Chromium, Firefox, WebKit)*
- A submenu the pointer opened is entered by the arrow toward it. *(Chromium, Firefox, WebKit)*
- Moving the pointer diagonally toward an open submenu, across other items, keeps it open. *(Chromium, Firefox, WebKit)*

### Touch

- A tap opens the menu, and a tap on an item chooses it. *(Chromium (touch), WebKit (touch))*
- On a phone, the menu rises from the bottom edge across the full width. *(Chromium (touch), WebKit (touch))*
- Every item is at least 44 pixels tall. *(Chromium (touch), WebKit (touch))*
- On a phone, a submenu takes the place of its menu: one sheet under one scrim, with nothing highlighted. *(Chromium (touch), WebKit (touch))*
- There it has a heading that says which submenu it is, and a way back that returns to the menu. *(Chromium (touch), WebKit (touch))*
- A tap on the scrim closes the submenu and its menu together. *(Chromium (touch), WebKit (touch))*
- Opened by a key there, a submenu opens on its first item, past the way back. *(Chromium (touch), WebKit (touch))*
- With a pointer a submenu has no way back in it: its menu is beside it. *(Chromium, Firefox, WebKit)*

### Items

- A key written as a symbol is written as text, never as an emoji.
- An item's shortcut is written after its label as its platform writes it, and told to assistive technology once.
- An item that leads somewhere is a link, and choosing it by key, click or drag follows it.
- When any item of a menu can be checked, every label in it begins at the same edge.

### Long menus

- A menu longer than the view stays within it and scrolls, keeping the item the keys move to in sight.
- A submenu of a menu that has scrolled still opens beside its item. *(Chromium, Firefox, WebKit)*

### Context menu

- A secondary click opens the menu at the pointer, with no item highlighted. *(Chromium, Firefox, WebKit)*
- A second secondary click elsewhere moves the menu there. *(Chromium, Firefox, WebKit)*
- Asked for by the keyboard, it opens against what has focus, on its first item.
- Choosing an item closes it, and so does Escape, and focus returns to what had it before.
- A press outside closes it, and does nothing to what it lands on. *(Chromium, Firefox, WebKit)*
- The browser's own menu gives way only when this one opens.
- A secondary press is first the list's, which selects what it is on, and then the menu opens. *(Chromium, Firefox, WebKit)*
- A finger that rests opens it, without waiting for a browser that brings no event for that. *(Chromium (touch), WebKit (touch))*
- A finger that rests on a part held to be dragged opens nothing: it has not moved yet. *(Chromium (touch), WebKit (touch))*
- A finger that moves on before it has rested opens nothing. *(Chromium (touch), WebKit (touch))*
- Has no accessibility violations when open.

## Reference implementation

React: `npx shadcn@latest add https://ui.publictheta.com/r/menu.json`
