Menu native
A menu of actions, checkboxes, groups and one-level submenus: opened by pressing its child (or a default button) or by right-click / long-press on it.
createSurface + updateComponents, A2UI v0.9.
[
{
"version": "v0.9",
"createSurface": {
"surfaceId": "preview",
"catalogId": "https://ui.exponential.at/catalogs/core/v1"
}
},
{
"version": "v0.9",
"updateComponents": {
"surfaceId": "preview",
"components": [
{
"id": "root",
"component": "Stack",
"direction": "vertical",
"align": "start",
"children": [
"example"
]
},
{
"id": "example",
"component": "Menu",
"label": "More",
"items": [
{
"label": "Rename",
"value": "rename"
},
{
"label": "Delete",
"value": "delete",
"destructive": true
}
],
"children": [
"c0-trigger"
]
},
{
"id": "c0-trigger",
"component": "Button",
"label": "More",
"variant": "outline"
}
]
}
}
]This surface through a MemoryTransport. Install and transports: React guide.
This surface through a MemoryTransport. Install and transports: SwiftUI guide.
This surface through a MemoryTransport. Install and transports: Compose guide.
This surface through a MemoryTransport. Install and transports: gpui guide.




View exponential-ui-menu, painted by each native renderer.
| Prop | Type | Default | Description |
|---|---|---|---|
label | string | – | The default trigger's text when no child is given. |
icon | icon | – | The default trigger's icon. |
itemsrequired | [menuItem] | – | The entries in order. |
openOn | press | contextmenu | "press" | A press on the child, or the context gesture over it. |
| Name | Kind |
|---|---|
on.select | event: runs an action |
- Role
menu- Semantics
- menu / menuitem / menuitemcheckbox / group / separator;
openOn: contextmenuopens at the pointer
| Keys | Action |
|---|---|
| EnterSpaceArrowDown on the trigger | open on the first item; ArrowUp: open on the last |
| – | Shift+F10 or the Menu key on the focused child (contextmenu): open at the child |
| ArrowDownArrowUp | next/previous item (wraps, skips disabled) |
| HomeEnd | first/last item |
| EnterSpace | run the item (a checkbox item toggles and stays open) |
| ArrowRight on a submenu | open it; ArrowLeft or Escape inside: close it |
| Escape | close and return focus to the trigger |
| Typing a letter | the next item starting with it |
- Recipe parts
Menu/triggerMenu/contentMenu/itemMenu/separatorMenu/labelMenu/shortcutMenu/checkMenu/submenuIndicator- Keyed by
openOn:hover:pressed:focus:disabled:checked:open:selected:invalid:dragover
Menu
The one floating-menu surface (opaque card fill, hairline, radius 12, no blur, no shadow) and the one ROW recipe on it, in two densities from tokens.json `menu`: POINTER for web from md up (36 row · 8 pad · 8 gap · 16 glyph · 180–280 wide), TOUCH for mobile web, iOS and Android (48 row · 12 pad · 12 gap · 16 glyph · 180–280 wide).
More
Every menu-like row on web reads the same --menu-* vars — context and dropdown items, their sub-triggers, Select, Command, the typeahead — so one change moves every menu. A destructive row is red and never fenced off by a divider (EXP-687).
Menupackages/ui/src/menu.tsxEXP-1249: ONE data-driven Menu (MenuEntry[], trigger | pointer | sheet) over the SDK menu + sheet primitives; rows wear menu-surface's --menu-* constants
GlassMenuDefaultsapps/android/app/src/main/java/com/exponential/app/ui/components/GlassMenu.ktthe touch set: M3's 48dp rows, 12dp padding
menu::pointerapps/desktop/crates/theme/src/tokens.generated.rsgpui-component's PopupMenu draws 26px rows / 8px pad from the crate; the tokens record 36 / 8
Menu · Picker · Typeahead
EXP-1074/1249: ONE data-driven Menu for every action menu, a list of MenuEntry rows (item, submenu with more rows or a picker body, toggle, separator, header) under one renderer in three modes: TRIGGER (a dropdown at a button), POINTER (a context menu at the pointer; one gesture host per layout, a row opts in with menuProps(kind, id)) and SHEET (the same rows as a bottom sheet below md, submenus as pushed pages).
More
Every row is the one --menu-* recipe (pointer 36 · 8 · 8 · 16, touch 48 · 12 · 12 · 16), a destructive row red with no divider above it (EXP-687). A submenu's picker body is PickerMenuRows, and Menu, Picker and the typeahead speak ONE highlight language: single = a trailing check, multi = the row's wash, mixed = a softer wash. In the catalog: `Menu` (`openOn: press | contextmenu`, submenu `items` bindable to a host source) and `Select`.
Menu / MenuGestureHost / MenuPanelpackages/ui/src/menu.tsxrows wear MENU_ITEM_CLASS (packages/exponential-ui-react/src/primitives/menu-surface.ts)
GlassDropdownMenuapps/android/app/src/main/java/com/exponential/app/ui/components/GlassMenu.ktthe touch set: M3's 48dp rows, 12dp padding
PopupMenu + controls::PointerMenu / pointer_label_itemapps/desktop/crates/ui/src/controls.rsissue, tab, file and run menus point; settings, actions and team menus still plain crate rows
- apps/desktop/crates/ui/src/controls.rs: gpui-component's PopupMenu draws 26px rows / 8px pad from the crate; the tokens record 36 / 8 (a leftover by decision)