The main menu is part of every app on macOS, and as of version 26, on iPadOS too. It’s the place where users will look to discover functionalities and ways to handle an app. For developers, knowing how to create additional menus, appending menu items in existing menus, and managing existing items, is a must-have skill. SwiftUI makes it really easy to deal with the main menu, so just read on for an exploration on all the essential details.
☝️ Note:
At the time of writing this post, macOS 26 is still in beta version. So, almost all given examples and screenshots next regard the current stable version, macOS 15. However, everything you’ll read, also works as of macOS 26 too.
Creating a new menu
Managing menus and items on the main menu is done using the commands modifier in the main scene of the app:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
@main struct CommandsDemoApp: App { var body: some Scene { WindowGroup { ContentView() } .commands { // Manage menus here… } } } |
To create a new menu, we use a particular container view inside the commands closure, the CommandMenu(_:content:). The first argument is the menu title, and the second it’s a closure where we define the various menu items.
Say, for instance, that we’re implementing a tasks app, and we need to create a new menu in order to create, edit, and delete a task. The following piece of code does that:
|
1 2 3 4 5 6 7 8 9 10 11 |
.commands { CommandMenu(“Task”) { Button(“Create”) { } Button(“Edit”) { } Button(“Delete”) { } } } |

See that each menu item is simply a button; the default control that triggers an action in SwiftUI. Prior to macOS 26, providing an image along with the button’s title would have no effect. However, as of macOS 26, provided images will show up next to the titles, as long as we use button initializers that support it:
|
1 2 3 4 5 6 7 8 9 |
CommandMenu(“Task”) { Button(“Create”, systemImage: “plus”) { } Button(“Edit”, systemImage: “pencil”) { } Button(“Delete”, systemImage: “trash”) { } } |

Separating menu items visually
Menu items are presented one after the other. However, it’s sometimes necessary to separate them visually, so we highlight the different purpose of the items. It’s really easy to achieve that using the Divider view.
Suppose that we want to separate the delete action in the previous example. All we have to do is to add a divider right before the delete button:
|
1 2 3 4 5 6 7 8 9 10 11 |
CommandMenu(“Task”) { Button(“Create”) { } Button(“Edit”) { } Divider() Button(“Delete”) { } } |

Creating submenus
Menus don’t have only single menu items, but also submenus. They are useful when it makes sense to group together related functionalities.
To create a submenu, we initialize a Menu view among buttons, right where we need it to appear. In the task menu example, we can add a menu to set a task priority between the edit and delete buttons, separating it with dividers:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
CommandMenu(“Task”) { Button(“Create”) { } Button(“Edit”) { } Divider() Menu(“Priority”) { Button(“Low”) { } Button(“Normal”) { } Button(“High”) { } } Divider() Button(“Delete”) { } } |

A submenu can contain other submenus if necessary, but make sure you don’t nest too many of them.
Assigning keyboard shortcuts to menu items
Just like it happens with built-in menu items, we can assign keyboard shortcuts to menus. By doing that, app’s functionalities become accessible from keyboard as well, and that’s essential for all macOS apps.
We can assign any letter key to a menu item, which we can also combine with modifier keys (command, shift, control). We can also assign special keys, such as the Return or Delete. However, the selection we make might not be available, as system menus may already make use of it.
Continuing on the same example, let’s add a keyboard shortcut to the create task menu item:
|
1 2 3 4 5 6 |
Button(“Create”) { } .keyboardShortcut(“n”, modifiers: [.command, .shift]) |
If that app was real, users would be able to create a new task simply by pressing Command + Shift + N simultaneously from now on.
Notice that we could have selected a simpler key combination, such as Command + N, but that’s already taken by the system, so we add one more modifier to the mix.
Note that the assigned key or key combination is presented right next to the respective menu item:

If the selected key is combined with a single modifier, then it’s not necessary to provide a collection to the modifiers parameter, just the modifier we’d like to use. For instance, let’s make the edit task menu item also work when pressing the Command + E key combination:
|
1 2 3 4 |
Button(“Edit”) { } .keyboardShortcut(“e”, modifiers: .command) |
Before we close this part, remember that special keys can be used too, which are suggested by Xcode if we just type the “.” (dot) symbol instead of providing a letter:
|
1 2 3 4 5 6 |
Button(“Delete”) { } .keyboardShortcut(.delete) |
The purpose of the above is to delete a task in the example scenario simply by pressing the backspace key on the keyboard. However, if the key is not available and we don’t specify modifiers manually (just like it happens here), the system will add one, so there are no conflicts with the keyboard shortcuts. The .delete key selection is intentional here, as it’s not available by default, and the system will add the Command modifier automatically:

Replacing existing menu items
All macOS apps come with default menus and menu items, but it’s really rare to keep them as they are. Usually we want to replace them with other, more suitable to our apps menu items, and there’s a particular container view to do that; the CommandGroup(replacing:addition:).
The first argument is a value matching to an existing menu item. Xcode suggests them all if we start typing the “.” symbol as always. The second is a closure where we provide a button that replaces the original menu item.
Suppose that we want to replace the “New Window” menu item under the File menu with the “New Project” menu item. Here’s how to do it:
|
1 2 3 4 5 6 7 8 |
CommandGroup(replacing: .newItem) { Button(“New Project”) { } .keyboardShortcut(“n”, modifiers: .command) } |

The .newItem value matches to the “New Window” default menu item, which is replaced with the “New Project” item.
Appending menu items to system menus
Besides replacing system menu items, we can also insert our own among the built-in ones. There are two container views to do that, depending on whether we need to append the custom menu item before or after the system items:
CommandGroup(before:addition:)CommandGroup(after:addition:)
The following code adds a menu item after the various pasteboard handling menu items in the Edit menu (after, copy, paste, etc). Hypothetically, it clears all pasteboard data:
|
1 2 3 4 5 |
CommandGroup(after: .pasteboard) { Button(“Clear All”) { } } |

Removing system menu items
We’ve seen how to replace system menu items, and how to add our own among them. There are times, however, where all we need is to remove a menu item.
To manage that, we use the CommandGroup(replacing:addition:) container view again, but with one great difference; we leave the addition closure empty.
The following removes the help menu item from the Help system menu:
|
1 2 3 |
CommandGroup(replacing: .help) { } |
Wrapping up
Creating custom menus and menu items is not difficult. The commands(content:) view modifier applied on the main scene of the app (almost always the WindowGroup) provides the ground to set up new menus or interfere with the built-in ones. Just choose the appropriate container view from those presented in the previous parts. Undoubtedly, SwiftUI makes it really easy to manage the main menu. Thanks for reading!