Menu & MenuBar
Dropdown menus, context menus, cascading menus, and horizontal menu bars
Namespace: Beep.Skia.Controls — Inherits: MenuBar → MaterialControl → SkiaComponent
Table of Contents
Overview
The MenuBar and Menu controls provide a complete menu system rendered entirely with SkiaSharp. MenuBar is a horizontal strip of top-level menu items (File, Edit, View, etc.). Each top-level item opens a Menu popup containing MenuItem entries. The system supports cascading submenus, context menus triggered by right-click, keyboard navigation with mnemonics, and icons rendered alongside menu item text.
All menus are overlay components: they float above the canvas content and are managed by the OverlayManager. When a menu opens, it captures pointer events to handle item hover/press and auto-closes when focus is lost or an item is selected.
Cascading & Submenus
When a MenuItem has a non-empty Children list, the menu system automatically renders a right-arrow indicator and supports cascading submenus. Hovering over the parent item (or pressing Right arrow) opens the submenu to the right. The submenu is rendered as a separate overlay panel positioned adjacent to the parent item, and it inherits the same styling and interaction behavior.
Submenus can be nested to arbitrary depth, though MD3 guidelines recommend a maximum depth of two levels for usability.
Nested Submenus
var arrangeMenu = new MenuItem("Arrange");
arrangeMenu.Children.Add(new MenuItem("Bring to Front", () => BringToFront()));
arrangeMenu.Children.Add(new MenuItem("Send to Back", () => SendToBack()));
var orderSubmenu = new MenuItem("Order");
orderSubmenu.Children.Add(new MenuItem("Bring Forward", () => BringForward()));
orderSubmenu.Children.Add(new MenuItem("Send Backward", () => SendBackward()));
arrangeMenu.Children.Add(orderSubmenu);
menuBar.Items.Add(arrangeMenu);
Separators & Icons
Create a separator by setting IsSeparator = true. The text value is ignored; a 1px horizontal line is drawn using the Outline theme color with 8px vertical padding. Separators are not hoverable or selectable.
Icons are specified as SKPath objects. The menu system renders them at 18x18 pixels, left-aligned within a 36px icon column. Icon color is resolved from the current theme's OnSurface token, with OnSurfaceVariant used for disabled items.
Tip
To render Material Design icons, use SKPath.ParseSvgPathData() with the icon's SVG path data string. Beep.Skia includes a built-in Icons class with commonly used paths (see Beep.Skia.Icons).
Code Example
Full MenuBar with File, Edit, and Help Menus
var menuBar = new MenuBar
{
X = 0,
Y = 0,
Width = 800,
MenuBarHeight = 48f
};
menuBar.Initialize();
var fileMenu = new MenuItem("&File");
fileMenu.Children.Add(new MenuItem("&New", () => NewDocument())
{ Shortcut = "Ctrl+N" });
fileMenu.Children.Add(new MenuItem("&Open", () => OpenDocument())
{ Shortcut = "Ctrl+O" });
fileMenu.Children.Add(new MenuItem("", null) { IsSeparator = true });
fileMenu.Children.Add(new MenuItem("&Save", () => SaveDocument())
{ Shortcut = "Ctrl+S" });
fileMenu.Children.Add(new MenuItem("Save &As...", () => SaveAs())
{ Shortcut = "Ctrl+Shift+S" });
fileMenu.Children.Add(new MenuItem("", null) { IsSeparator = true });
fileMenu.Children.Add(new MenuItem("E&xit", () => ExitApp())
{ Shortcut = "Alt+F4" });
var editMenu = new MenuItem("&Edit");
editMenu.Children.Add(new MenuItem("&Undo", () => Undo())
{ Shortcut = "Ctrl+Z", IsEnabled = false });
editMenu.Children.Add(new MenuItem("&Redo", () => Redo())
{ Shortcut = "Ctrl+Y", IsEnabled = false });
var helpMenu = new MenuItem("&Help");
helpMenu.Children.Add(new MenuItem("&Documentation", () => OpenDocs()));
helpMenu.Children.Add(new MenuItem("&About", () => ShowAbout()));
menuBar.Items.Add(fileMenu);
menuBar.Items.Add(editMenu);
menuBar.Items.Add(helpMenu);
drawingManager.AddComponent(menuBar);
drawingManager.RequestRedraw();