Components / Overlays

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.

Replaces
ContextMenuDropdownMenu
Children
one
Loading the renderer…
Menu rendered by the React renderer on Web
Web React
Menu rendered by the SwiftUI renderer on iOS
iOS SwiftUI
Menu rendered by the Compose renderer on Android
Android Compose
Menu rendered by the gpui renderer on Desktop
Desktop gpui

View exponential-ui-menu, painted by each native renderer.

PropTypeDefaultDescription
labelstring–The default trigger's text when no child is given.
iconicon–The default trigger's icon.
itemsrequired[menuItem]–The entries in order.
openOnpress | contextmenu"press"A press on the child, or the context gesture over it.
NameKind
on.selectevent: runs an action
Role
menu
Semantics
menu / menuitem / menuitemcheckbox / group / separator; openOn: contextmenu opens at the pointer
KeysAction
EnterSpaceArrowDown on the triggeropen on the first item; ArrowUp: open on the last
–Shift+F10 or the Menu key on the focused child (contextmenu): open at the child
ArrowDownArrowUpnext/previous item (wraps, skips disabled)
HomeEndfirst/last item
EnterSpacerun the item (a checkbox item toggles and stays open)
ArrowRight on a submenuopen it; ArrowLeft or Escape inside: close it
Escapeclose and return focus to the trigger
Typing a letterthe 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

Themes · Write a theme

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).

Webok
Menupackages/ui/src/menu.tsx

EXP-1249: ONE data-driven Menu (MenuEntry[], trigger | pointer | sheet) over the SDK menu + sheet primitives; rows wear menu-surface's --menu-* constants

iOSok
GlassMenuTokensapps/ios/ExpUI/Sources/GlassMenu.swift

the touch set: 48pt rows, 12pt padding

Androidok
GlassMenuDefaultsapps/android/app/src/main/java/com/exponential/app/ui/components/GlassMenu.kt

the touch set: M3's 48dp rows, 12dp padding

Desktopleftover
menu::pointerapps/desktop/crates/theme/src/tokens.generated.rs

gpui-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`.

Webok
Menu / MenuGestureHost / MenuPanelpackages/ui/src/menu.tsx

rows wear MENU_ITEM_CLASS (packages/exponential-ui-react/src/primitives/menu-surface.ts)

iOSok
GlassMenuapps/ios/ExpUI/Sources/GlassMenu.swift

the touch set: 48pt rows, 12pt padding

Androidok
GlassDropdownMenuapps/android/app/src/main/java/com/exponential/app/ui/components/GlassMenu.kt

the touch set: M3's 48dp rows, 12dp padding

Desktopleftover
PopupMenu + controls::PointerMenu / pointer_label_itemapps/desktop/crates/ui/src/controls.rs

issue, tab, file and run menus point; settings, actions and team menus still plain crate rows