Menu

A list of actions or options opened from a trigger.

EXAMPLEwasm · webgpu

This demo runs the real GPUI component on WebGPU, which this browser does not expose.

Try Chrome or Edge 113+, or Safari 26+. In Firefox, enable dom.webgpu.enabled.

You can also run it natively: cargo run -p showcase menu

The demo failed to start in this browser.

You can run it natively instead: cargo run -p showcase menu

Live examples are not supported on most mobile browsers yet — open this page on a desktop or tablet to run the demo.

Recent phones with WebGPU may manage it (downloads ~18 MB):

#Anatomy

Import the component's parts and compose them under its root:

use base_gpui::menu::{
    MenuArrow,
    MenuBackdrop,
    MenuCheckboxItem,
    MenuCheckboxItemIndicator,
    MenuGroup,
    MenuGroupLabel,
    MenuItem,
    MenuLinkItem,
    MenuPopup,
    MenuPortal,
    MenuPositioner,
    MenuRadioGroup,
    MenuRadioItem,
    MenuRadioItemIndicator,
    MenuRoot,
    MenuSeparator,
    MenuSubmenuRoot,
    MenuSubmenuTrigger,
    MenuTrigger,
};

MenuRoot::new()
    .child(
        MenuRadioGroup::new()
                .child(
                    MenuGroupLabel::new(),
                )
                .child(
                    MenuRadioItem::new()
                                .child(
                                    MenuRadioItemIndicator::new(),
                                ),
                )
                .child(
                    MenuSeparator::new(),
                ),
    )
    .child(
        MenuTrigger::new(),
    );
The anatomy is a structural overview. Parts with mutually exclusive modes may need separate instances; each part's section below documents its configuration.

Coordinates the component's state and supplies context to its child parts.

Source

use base_gpui::menu::MenuRoot;

MenuRoot::new()
    .id("example-id")
    .default_open(true)
    .open(true)
    .trigger_id("example-id")
    .default_trigger_id("example-id")
    .disabled(true)
    .modal(true)
    .loop_focus(true)
    .orientation(/* orientation: MenuOrientation */)
    .close_parent_on_esc(true)
    .highlight_item_on_hover(true)
    .on_open_change(|/* callback arguments */| { /* handle change */ })
    .on_open_change_complete(|/* callback arguments */| { /* handle change */ })
    .style_with_state(|/* callback arguments */| { /* handle change */ })
    .context_menu_parent()
    .menubar_link(/* link: MenuMenubarLink */)
    .is_disabled();
BuilderSignature & description

Coordinates the component's state and supplies context to its child parts.

Source

use base_gpui::menu::MenuSubmenuRoot;

MenuSubmenuRoot::new()
    .id("example-id")
    .default_open(true)
    .open(true)
    .disabled(true)
    .loop_focus(true)
    .orientation(/* orientation: MenuOrientation */)
    .close_parent_on_esc(true)
    .highlight_item_on_hover(true)
    .on_open_change(|/* callback arguments */| { /* handle change */ })
    .on_open_change_complete(|/* callback arguments */| { /* handle change */ })
    .style_with_state(|/* callback arguments */| { /* handle change */ });
BuilderSignature & description

Interactive control that opens, closes, or activates the component.

Source

use base_gpui::menu::MenuSubmenuTrigger;

MenuSubmenuTrigger::new()
    .id("example-id")
    .label("label")
    .disabled(true)
    .open_on_hover(true)
    .delay(/* delay: Duration */)
    .close_delay(/* close_delay: Duration */)
    .label_value()
    .disabled_value()
    .open_on_hover_value()
    .delay_value()
    .close_delay_value()
    .wired(0, /* focus_handle: FocusHandle */)
    .with_contexts(/* parent: MenuContext<P> */, /* child */, 0)
    .style_with_state(|/* callback arguments */| { /* handle change */ });
BuilderSignature & description

Interactive control that opens, closes, or activates the component.

Source

use base_gpui::menu::MenuTrigger;

MenuTrigger::new()
    .id("example-id")
    .disabled(true)
    .payload(/* payload: P */)
    .open_on_hover(true)
    .delay(/* delay: Duration */)
    .close_delay(/* close_delay: Duration */)
    .aria_label("label")
    .style_with_state(|/* callback arguments */| { /* handle change */ });
BuilderSignature & description

Hosts overlay content outside the normal child layout.

Source

use base_gpui::menu::MenuPortal;

MenuPortal::new()
    .keep_mounted(true)
    .style_with_state(|/* callback arguments */| { /* handle change */ });
BuilderSignature & description

Measures the anchor and positions floating content.

Source

use base_gpui::menu::MenuPositioner;

MenuPositioner::new()
    .side("example-id")
    .align(/* align: MenuAlign */)
    .side_offset("example-id")
    .align_offset(/* align_offset: Pixels */)
    .collision_padding(/* collision_padding: Pixels */)
    .keep_mounted(true)
    .keep_mounted_from_portal()
    .style_with_state(|/* callback arguments */| { /* handle change */ });
BuilderSignature & description

Contains the floating interactive content.

Source

use base_gpui::menu::MenuPopup;

MenuPopup::new()
    .id("example-id")
    .keep_mounted(true)
    .style_with_state(|/* callback arguments */| { /* handle change */ });
BuilderSignature & description

Optional arrow that visually points toward the overlay anchor.

Source

use base_gpui::menu::MenuArrow;

MenuArrow::new()
    .style_with_state(|/* callback arguments */| { /* handle change */ });
BuilderSignature & description

Covers content behind a modal overlay and handles outside interaction.

Source

use base_gpui::menu::MenuBackdrop;

MenuBackdrop::new()
    .keep_mounted(true)
    .style_with_state(|/* callback arguments */| { /* handle change */ });
BuilderSignature & description

Represents one interactive item in the component's collection.

Source

use base_gpui::menu::MenuCheckboxItem;

MenuCheckboxItem::new()
    .id("example-id")
    .label("label")
    .disabled(true)
    .close_on_click(true)
    .checked(true)
    .default_checked(true)
    .on_checked_change(|/* callback arguments */| { /* handle change */ })
    .style_with_state(|/* callback arguments */| { /* handle change */ });
BuilderSignature & description

Visual indicator for an item's selected or checked state.

Source

use base_gpui::menu::MenuCheckboxItemIndicator;

MenuCheckboxItemIndicator::new()
    .keep_mounted(true)
    .with_item_facts(true, true, true)
    .style_with_state(|/* callback arguments */| { /* handle change */ });
BuilderSignature & description

Groups related child parts and coordinates their shared behavior.

Source

use base_gpui::menu::MenuGroup;

MenuGroup::new()
    .id("example-id")
    .aria_label("label")
    .style_with_state(|/* callback arguments */| { /* handle change */ });
BuilderSignature & description

Provides a visible label and associated accessibility semantics.

Source

use base_gpui::menu::MenuGroupLabel;

MenuGroupLabel::new()
    .label("label")
    .label_value()
    .style_with_state(|/* callback arguments */| { /* handle change */ });
BuilderSignature & description

Represents one interactive item in the component's collection.

Source

use base_gpui::menu::MenuItem;

MenuItem::new()
    .id("example-id")
    .label("label")
    .disabled(true)
    .close_on_click(true)
    .on_click(|/* callback arguments */| { /* handle change */ })
    .style_with_state(|/* callback arguments */| { /* handle change */ });
BuilderSignature & description

Represents one interactive item in the component's collection.

Source

use base_gpui::menu::MenuLinkItem;

MenuLinkItem::new()
    .id("example-id")
    .label("label")
    .close_on_click(true)
    .on_activate(|/* callback arguments */| { /* handle change */ })
    .style_with_state(|/* callback arguments */| { /* handle change */ });
BuilderSignature & description

Groups related child parts and coordinates their shared behavior.

Source

use base_gpui::menu::MenuRadioGroup;

MenuRadioGroup::new()
    .id("example-id")
    .aria_label("label")
    .value(None)
    .default_value(None)
    .disabled(true)
    .on_value_change(|/* callback arguments */| { /* handle change */ })
    .style_with_state(|/* callback arguments */| { /* handle change */ });
BuilderSignature & description

Represents one interactive item in the component's collection.

Source

use base_gpui::menu::MenuRadioItem;

MenuRadioItem::new()
    .prepare_for_group(0, true, None, None)
    .wired_index()
    .item_value()
    .id("example-id")
    .value(/* value: V */)
    .label("label")
    .disabled(true)
    .close_on_click(true)
    .style_with_state(|/* callback arguments */| { /* handle change */ });
BuilderSignature & description

Visual indicator for an item's selected or checked state.

Source

use base_gpui::menu::MenuRadioItemIndicator;

MenuRadioItemIndicator::new()
    .keep_mounted(true)
    .with_item_facts(true, true, true)
    .style_with_state(|/* callback arguments */| { /* handle change */ });
BuilderSignature & description

Visual separator between neighboring items or groups.

Source

use base_gpui::menu::MenuSeparator;

MenuSeparator::new()
    .orientation(/* orientation: SeparatorOrientation */)
    .style_with_state(|/* callback arguments */| { /* handle change */ });
BuilderSignature & description

#Accessibility

Keyboard interaction and accessibility semantics are implemented by the component, independently of visual styling. Known limitations caused by missing GPUI accessibility primitives are documented in the module source and are not silently approximated.

The menu family sets Role::Button/Role::MenuItem on triggers, Role::Menu on popups, Role::MenuItem{,CheckBox,Radio} on items, and Role::Group on (radio) groups. Backdrop, arrow, indicators, group label, portal, positioner, and the structural roots carry no role and stay out of the accessibility tree (mirroring Base UI's role="presentation" / aria-hidden). Gaps in the pinned gpui revision, omitted rather than faked (blocked on upstream builders): - aria-haspopup="menu" / aria-controls on triggers and submenu triggers: aria_expanded plus the popup's Role::Menu stand in. - aria-labelledby: replaced by literal-string .aria_label(...) sourced from the registered group-label metadata. - disabled/aria-disabled: disabled parts are inert (withheld tab stops, activation no-ops) but the disabled state is not announced.

#Stability

Base GPUI is pre-1.0. Builder names and state types may evolve as GPUI and this port mature.