Menu
Anatomy
Dropdown menu for actions and navigation. Supports items, separators, labels, checkboxes, radio groups, submenus, and grouping.
maud_ui::primitives::menu
Props
Generated from public Rust fields. Defaults are evaluated from the implementation.
| Prop | Type | Default | Description |
|---|---|---|---|
trigger_label | String | No struct Default; supply explicitly | Text displayed on the trigger button |
id | String | No struct Default; supply explicitly | Unique identifier for the menu |
items | Vec<MenuEntry> | No struct Default; supply explicitly | Menu entries (items, separators, and labels) |
Examples
File menu
User menu
View menu — checkbox + radio + submenu
Usage and composition
Import
use maud_ui::primitives::menu::{self, Props, MenuItem, MenuEntry, RadioItem};
Example
use maud::html;
use maud_ui::primitives::menu;
html! {
(menu::render(menu::Props {
trigger_label: "Actions".into(),
id: "demo-menu".into(),
items: vec![
menu::MenuEntry::Item(menu::MenuItem {
label: "Edit".into(),
action: "edit".into(),
disabled: false,
destructive: false,
shortcut: Some("⌘E".into()),
}),
menu::MenuEntry::Separator,
menu::MenuEntry::Item(menu::MenuItem {
label: "Delete".into(),
action: "delete".into(),
disabled: false,
destructive: true,
shortcut: None,
}),
],
}))
}
MenuEntry Enum
The MenuEntry enum defines the structure of menu items. All variants are fully supported:
MenuEntry::Item(MenuItem)
A simple clickable menu item.
pub struct MenuItem {
pub label: String, // Item text
pub action: String, // Data attribute for event handling
pub disabled: bool, // Disabled state
pub destructive: bool, // Red danger styling (e.g., delete)
pub shortcut: Option<String>, // Keyboard shortcut display (e.g., "⌘Z")
}
MenuEntry::Separator
A visual divider between menu sections.
MenuEntry::Label(String)
A non-interactive label or heading for grouping related items.
MenuEntry::CheckboxItem
A menu item with toggle state (on/off).
MenuEntry::CheckboxItem {
label: String, // Item text
checked: bool, // Current state
disabled: bool, // Disabled state
shortcut: Option<String>, // Optional keyboard shortcut
}
MenuEntry::RadioGroup
A named group of mutually exclusive radio options.
MenuEntry::RadioGroup {
name: String, // Group identifier
items: Vec<RadioItem>, // Radio options
}
Where RadioItem is:
pub struct RadioItem {
pub label: String, // Option text
pub value: String, // Option value
pub checked: bool, // Currently selected
pub disabled: bool, // Disabled state
pub shortcut: Option<String>, // Optional keyboard shortcut
}
MenuEntry::Sub
A submenu trigger with nested menu entries.
MenuEntry::Sub {
trigger_label: String, // Submenu trigger text
items: Vec<MenuEntry>, // Nested menu entries (any MenuEntry variant)
}
Submenus can be nested arbitrarily deep.
MenuEntry::Group
A generic grouping wrapper (renders with role="group").
MenuEntry::Group {
items: Vec<MenuEntry>, // Grouped entries
}
Variants
| Variant | Use Case |
|---|---|
| Item | Primary menu action. |
| Item (destructive) | Dangerous action requiring confirmation (delete, remove, etc.). |
| Separator | Visual divider between logical sections. |
| Label | Section header or grouping label. |
| CheckboxItem | Toggle option (show/hide, enable/disable feature). |
| RadioGroup | Single-selection option group (e.g., theme, position). |
| Sub | Nested menu with additional options. |
| Group | Container for related menu entries. |
Helpers
render_entry(entry: &MenuEntry) -> Markup
Renders a single menu entry. Used internally and can be used in custom menu construction. Public for composability.
Related
Context Menu, Menubar, Button.
Shadcn reference
https://ui.shadcn.com/docs/components/base/dropdown-menu
Accessibility
- Trigger button: Sets
aria-expanded="false"(true when open),aria-haspopup="menu", andaria-controlspointing to the menu content. - Menu roles: Menu items use
role="menuitem", checkboxes userole="menuitemcheckbox"witharia-checked, radio buttons userole="menuitemradio"witharia-checked, and separators userole="separator". - Keyboard navigation: Tabindex is set to
-1for all menu items; keyboard navigation (arrow keys, Enter, Escape) is handled via JavaScript. - Shortcuts: Displayed as decorative text; not enforced by the component (handled by application).
- Screen readers: Labels are announced for all entry types; separators are marked as decorative.