Menu Reference
Complete reference for menu item types and properties.
Professional desktop applications need menu bars—File, Edit, View, Help. But menus work differently on each platform:
Building platform-appropriate menus manually is tedious and error-prone.
Wails provides a unified API that creates platform-native menus automatically. Write once, get native behaviour on all platforms.
package main
import ( "runtime" "github.com/wailsapp/wails/v3/pkg/application")
func main() { app := application.New(application.Options{ Name: "My App", })
// Create menu menu := app.NewMenu()
// Add standard menus (platform-appropriate) if runtime.GOOS == "darwin" { menu.AddRole(application.AppMenu) // macOS only } menu.AddRole(application.FileMenu) menu.AddRole(application.EditMenu) menu.AddRole(application.WindowMenu) menu.AddRole(application.HelpMenu)
// Set the application menu app.Menu.Set(menu)
// Create window with UseApplicationMenu to inherit the menu on Windows/Linux app.Window.NewWithOptions(application.WebviewWindowOptions{ UseApplicationMenu: true, })
app.Run()}That’s it! You now have platform-native menus with standard items. The UseApplicationMenu option ensures Windows and Linux windows display the menu without additional code.
// Create a new menumenu := app.NewMenu()
// Add a top-level menufileMenu := menu.AddSubmenu("File")
// Add menu itemsfileMenu.Add("New").OnClick(func(ctx *application.Context) { // Handle New})
fileMenu.Add("Open").OnClick(func(ctx *application.Context) { // Handle Open})
fileMenu.AddSeparator()
fileMenu.Add("Quit").OnClick(func(ctx *application.Context) { app.Quit()})Recommended approach — Use UseApplicationMenu for cross-platform consistency:
// Set the application menu onceapp.Menu.Set(menu)
// Create windows that inherit the menu on Windows/Linuxapp.Window.NewWithOptions(application.WebviewWindowOptions{ UseApplicationMenu: true, // Window uses the app menu})This approach:
UseApplicationMenu: true displays the app menuPlatform-specific details:
Global menu bar (one per application):
app.Menu.Set(menu)The menu appears at the top of the screen and persists even when all windows are closed. The UseApplicationMenu option has no effect on macOS since all apps use the global menu.
Per-window menu bar:
// Option 1: Use application menu (recommended)app.Menu.Set(menu)window := app.Window.NewWithOptions(application.WebviewWindowOptions{ UseApplicationMenu: true,})
// Option 2: Set menu directly on windowwindow.SetMenu(menu)Each window can have its own menu, or inherit the application menu. The menu appears in the window’s title bar.
Per-window menu bar (usually):
// Option 1: Use application menu (recommended)app.Menu.Set(menu)window := app.Window.NewWithOptions(application.WebviewWindowOptions{ UseApplicationMenu: true,})
// Option 2: Set menu directly on windowwindow.SetMenu(menu)Behaviour varies by desktop environment. Some (like Unity) support global menus.
Per-window custom menus:
If a window needs a different menu than the application menu, set it directly:
window.SetMenu(customMenu) // Overrides UseApplicationMenuWails provides predefined menu roles that create platform-appropriate menu structures automatically.
| Role | Description | Platform Notes |
|---|---|---|
AppMenu | Application menu with About, Preferences, Quit | macOS only |
FileMenu | File operations (New, Open, Save, etc.) | All platforms |
EditMenu | Text editing (Undo, Redo, Cut, Copy, Paste) | All platforms |
WindowMenu | Window management (Minimise, Zoom, etc.) | All platforms |
HelpMenu | Help and information | All platforms |
menu := app.NewMenu()
// macOS: Add application menuif runtime.GOOS == "darwin" { menu.AddRole(application.AppMenu)}
// All platforms: Add standard menusmenu.AddRole(application.FileMenu)menu.AddRole(application.EditMenu)menu.AddRole(application.WindowMenu)menu.AddRole(application.HelpMenu)What you get:
AppMenu (with app name):
FileMenu:
EditMenu:
WindowMenu:
HelpMenu:
FileMenu:
EditMenu:
WindowMenu:
HelpMenu:
Similar to Windows, but keyboard shortcuts may vary by desktop environment.
Add items to role menus:
fileMenu := menu.AddRole(application.FileMenu)
// Add custom itemsfileMenu.Add("Import...").OnClick(handleImport)fileMenu.Add("Export...").OnClick(handleExport)Create your own menus for application-specific features:
// Add a custom top-level menutoolsMenu := menu.AddSubmenu("Tools")
// Add itemstoolsMenu.Add("Settings").OnClick(func(ctx *application.Context) { showSettingsWindow()})
toolsMenu.AddSeparator()
// Add checkboxtoolsMenu.AddCheckbox("Dark Mode", false).OnClick(func(ctx *application.Context) { isDark := ctx.ClickedMenuItem().Checked() setTheme(isDark)})
// Add radio grouptoolsMenu.AddRadio("Small", true).OnClick(handleFontSize)toolsMenu.AddRadio("Medium", false).OnClick(handleFontSize)toolsMenu.AddRadio("Large", false).OnClick(handleFontSize)
// Add submenuadvancedMenu := toolsMenu.AddSubmenu("Advanced")advancedMenu.Add("Configure...").OnClick(showAdvancedSettings)For more menu item types, see Menu Reference.
Update menus based on application state:
var saveMenuItem *application.MenuItem
func createMenu() { menu := app.NewMenu() fileMenu := menu.AddSubmenu("File")
saveMenuItem = fileMenu.Add("Save") saveMenuItem.SetEnabled(false) // Initially disabled saveMenuItem.OnClick(handleSave)
app.SetMenu(menu)}
func onDocumentChanged() { saveMenuItem.SetEnabled(hasUnsavedChanges()) menu.Update() // Important!}updateMenuItem := menu.Add("Check for Updates")
updateMenuItem.OnClick(func(ctx *application.Context) { updateMenuItem.SetLabel("Checking...") menu.Update()
checkForUpdates()
updateMenuItem.SetLabel("Check for Updates") menu.Update()})For major changes, rebuild the entire menu:
func rebuildFileMenu() { menu := app.NewMenu() fileMenu := menu.AddSubmenu("File")
fileMenu.Add("New").OnClick(handleNew) fileMenu.Add("Open").OnClick(handleOpen)
// Add recent files dynamically if hasRecentFiles() { recentMenu := fileMenu.AddSubmenu("Open Recent") for _, file := range getRecentFiles() { filePath := file // Capture for closure recentMenu.Add(filepath.Base(file)).OnClick(func(ctx *application.Context) { openFile(filePath) }) } recentMenu.AddSeparator() recentMenu.Add("Clear Recent").OnClick(clearRecentFiles) }
fileMenu.AddSeparator() fileMenu.Add("Quit").OnClick(func(ctx *application.Context) { app.Quit() })
app.SetMenu(menu)}Menu items can control windows:
viewMenu := menu.AddSubmenu("View")
// Toggle fullscreenviewMenu.Add("Toggle Fullscreen").OnClick(func(ctx *application.Context) { window := app.GetWindowByName("main") window.SetFullscreen(!window.IsFullscreen())})
// Zoom controlsviewMenu.Add("Zoom In").SetAccelerator("CmdOrCtrl++").OnClick(func(ctx *application.Context) { // Increase zoom})
viewMenu.Add("Zoom Out").SetAccelerator("CmdOrCtrl+-").OnClick(func(ctx *application.Context) { // Decrease zoom})
viewMenu.Add("Reset Zoom").SetAccelerator("CmdOrCtrl+0").OnClick(func(ctx *application.Context) { // Reset zoom})Get the active window:
menuItem.OnClick(func(ctx *application.Context) { window := application.ContextWindow(ctx) // Use window})Menu bar behaviour:
menu.AddRole(application.AppMenu) for standard itemsStandard locations:
Example:
if runtime.GOOS == "darwin" { menu.AddRole(application.AppMenu) // Adds About, Preferences, Quit
// Don't add Quit to File menu on macOS // Don't add About to Help menu on macOS}Menu bar behaviour:
Standard locations:
Example:
if runtime.GOOS == "windows" { fileMenu := menu.AddRole(application.FileMenu) // Exit is added automatically
helpMenu := menu.AddRole(application.HelpMenu) // About is added automatically}Menu bar behaviour:
Best practice: Follow Windows conventions, test on target DEs.
Here’s a production-ready menu structure:
package main
import ( "runtime" "github.com/wailsapp/wails/v3/pkg/application")
func main() { app := application.New(application.Options{ Name: "My Application", })
// Create and set menu createMenu(app)
// Create main window with UseApplicationMenu for cross-platform menu support app.Window.NewWithOptions(application.WebviewWindowOptions{ UseApplicationMenu: true, })
app.Run()}
func createMenu(app *application.Application) { menu := app.NewMenu()
// Platform-specific application menu (macOS only) if runtime.GOOS == "darwin" { menu.AddRole(application.AppMenu) }
// File menu fileMenu := menu.AddRole(application.FileMenu) fileMenu.Add("Import...").SetAccelerator("CmdOrCtrl+I").OnClick(handleImport) fileMenu.Add("Export...").SetAccelerator("CmdOrCtrl+E").OnClick(handleExport)
// Edit menu menu.AddRole(application.EditMenu)
// View menu viewMenu := menu.AddSubmenu("View") viewMenu.Add("Toggle Fullscreen").SetAccelerator("F11").OnClick(toggleFullscreen) viewMenu.AddSeparator() viewMenu.AddCheckbox("Show Sidebar", true).OnClick(toggleSidebar) viewMenu.AddCheckbox("Show Toolbar", true).OnClick(toggleToolbar)
// Tools menu toolsMenu := menu.AddSubmenu("Tools")
// Settings location varies by platform if runtime.GOOS == "darwin" { // On macOS, Preferences is in Application menu (added by AppMenu role) } else { toolsMenu.Add("Settings").SetAccelerator("CmdOrCtrl+,").OnClick(showSettings) }
toolsMenu.AddSeparator() toolsMenu.AddCheckbox("Dark Mode", false).OnClick(toggleDarkMode)
// Window menu menu.AddRole(application.WindowMenu)
// Help menu helpMenu := menu.AddRole(application.HelpMenu) helpMenu.Add("Documentation").OnClick(openDocumentation)
// About location varies by platform if runtime.GOOS == "darwin" { // On macOS, About is in Application menu (added by AppMenu role) } else { helpMenu.AddSeparator() helpMenu.Add("About").OnClick(showAbout) }
// Set the application menu app.Menu.Set(menu)}
func handleImport(ctx *application.Context) { // Implementation}
func handleExport(ctx *application.Context) { // Implementation}
func toggleFullscreen(ctx *application.Context) { window := application.ContextWindow(ctx) window.SetFullscreen(!window.IsFullscreen())}
func toggleSidebar(ctx *application.Context) { // Implementation}
func toggleToolbar(ctx *application.Context) { // Implementation}
func showSettings(ctx *application.Context) { // Implementation}
func toggleDarkMode(ctx *application.Context) { isDark := ctx.ClickedMenuItem().Checked() // Apply theme}
func openDocumentation(ctx *application.Context) { // Open browser}
func showAbout(ctx *application.Context) { // Show about dialog}CmdOrCtrlMenu Reference
Complete reference for menu item types and properties.
Context Menus
Create right-click context menus.
System Tray Menus
Add system tray/menu bar integration.
Menu Patterns
Common menu patterns and best practices.
Questions? Ask in Discord or check the menu example.