Provide a declarative API for menus: a horizontal <MenuBar> that hosts one or more dropdown <Menu text="..."> groups, each containing actionable <MenuButton> items (and optional nested submenus). Map directly to ui.menu_bar(...) and ui.menu_button(...), with ergonomic events and diagnostics.
- Menus are a staple of desktop-style UIs (File/Edit/View…); EFx should support them first-class.
- Reduce imperative glue by letting templates define full menu structures.
- Enable nested submenus and disabled items with predictable behavior.
Scope
-
New tags:
<MenuBar>: container rendering a horizontal menubar.
<Menu text="..."> ... </Menu>: dropdown menu opener (label in the bar; content shown on open).
<MenuButton onClick={|| ...}>Label</MenuButton>: clickable action inside a menu.
-
Optional attributes:
<MenuBar>: id, class, tooltip (applied to the bar area).
<Menu>: text (required), id, enabled=bool, tooltip.
<MenuButton>: text (alt to children), enabled=bool, shortcut="Ctrl+O", closeOnClick=bool (default: true), tooltip.
-
Supported children:
<MenuBar> → one or more <Menu> (and optionally <Separator/> between menus is ignored visually).
<Menu> → <MenuButton>, nested <Menu> (submenu), <Separator/>.
<MenuButton> → text as children (or text="...", mutually exclusive).
Non-goals (here):
- Automatic accelerator handling (keyboard shortcuts are displayed textually only).
- Iconography and custom item widgets (can be added later).
- Platform-level menu integration (native menus).
Proposed API (sketch)
Basic menubar
efx!(ui, r#"
<MenuBar>
<Menu text="File">
<MenuButton onClick={|| new_file()}>New</MenuButton>
<MenuButton onClick={|| open_file()} shortcut="Ctrl+O">Open…</MenuButton>
<Separator/>
<MenuButton onClick={|| quit()} shortcut="Ctrl+Q">Quit</MenuButton>
</Menu>
<Menu text="Edit">
<MenuButton onClick={|| undo()} shortcut="Ctrl+Z">Undo</MenuButton>
<MenuButton onClick={|| redo()} shortcut="Ctrl+Shift+Z">Redo</MenuButton>
</Menu>
</MenuBar>
"#);
Nested submenu & disabled item
efx!(ui, r#"
<MenuBar>
<Menu text="View">
<Menu text="Theme">
<MenuButton onClick={|| set_theme("Light")}>Light</MenuButton>
<MenuButton onClick={|| set_theme("Dark")}>Dark</MenuButton>
</Menu>
<Separator/>
<MenuButton enabled="false" tooltip="No layout available">Reset Layout</MenuButton>
</Menu>
</MenuBar>
"#);
Conceptual mapping to egui
ui.menu_bar(|ui| {
// <Menu text="...">
ui.menu_button(text, |ui| {
// <MenuButton> → if ui.button(label).clicked() { if close_on_click { ui.close_menu(); } onClick(); }
// <Menu> (nested) → ui.menu_button(...)
// <Separator/> → ui.separator();
});
});
Tasks
Provide a declarative API for menus: a horizontal
<MenuBar>that hosts one or more dropdown<Menu text="...">groups, each containing actionable<MenuButton>items (and optional nested submenus). Map directly toui.menu_bar(...)andui.menu_button(...), with ergonomic events and diagnostics.Scope
New tags:
<MenuBar>: container rendering a horizontal menubar.<Menu text="..."> ... </Menu>: dropdown menu opener (label in the bar; content shown on open).<MenuButton onClick={|| ...}>Label</MenuButton>: clickable action inside a menu.Optional attributes:
<MenuBar>:id,class,tooltip(applied to the bar area).<Menu>:text(required),id,enabled=bool,tooltip.<MenuButton>:text(alt to children),enabled=bool,shortcut="Ctrl+O",closeOnClick=bool(default: true),tooltip.Supported children:
<MenuBar>→ one or more<Menu>(and optionally<Separator/>between menus is ignored visually).<Menu>→<MenuButton>, nested<Menu>(submenu),<Separator/>.<MenuButton>→ text as children (ortext="...", mutually exclusive).Non-goals (here):
Proposed API (sketch)
Basic menubar
Nested submenu & disabled item
Conceptual mapping to egui
Tasks
AST & validation
<MenuBar>,<Menu>,<MenuButton>.<Menu>only inside<MenuBar>or another<Menu>;<MenuButton>only inside<Menu>.<MenuButton>: children ortext=....Codegen
<MenuBar>→ui.menu_bar(|ui| { ... }).<Menu text="...">→ui.menu_button(text, |ui| { ... })withenabled/tooltip.<MenuButton>:ui.button(label); honorenabledviaui.add_enabled(...).shortcutpresent, append right-aligned hint to the label (e.g.,"Open…\tCtrl+O"or two-column layout if feasible).onClick; ifcloseOnClick != false, callui.close_menu().tooltipviaResponse::on_hover_text.Diagnostics
<MenuButton>outside<Menu>) → clear error with expected parents.texton<Menu>→ required attribute message.text=on<MenuButton>→ actionable error.Examples & docs
examples/menu_bar.rs: File/Edit/View with nested Theme submenu; disabled item; shortcuts.Tests
wasm32-unknown-unknown(no runtime launch).