NSHostingMenu
An AppKit menu with menu items that are defined by a SwiftUI View.
Declaration
class NSHostingMenu<Content> where Content : ViewOverview
Because NSHostingMenu is an NSMenu subclass, you can integrate it into your existing AppKit view hierarchies that display menus. For example, you can set a hosting menu as an AppKit view’s context menu.
A hosting menu’s items property will be updated based on the content of the provided rootView, so direct mutations to the item array are not allowed, even if done using methods like addItem on the menu itself.
SwiftUI views hosted in the menu will be styled and behave identically to views in a Menu or View/contextMenu. Make sure to use a Group or a view with multiple subviews as your top level container instead of an HStack or other container that would attempt to place all of your actions in a single menu item.
For example, the following code would set up the first part of the Finder’s context menu, both in the Action button in the toolbar and as a context menu:
struct FileOrFolderContextMenu: View {
let url: URL
var body: some View {
Section {
if url.hasDirectoryPath {
Button("Open in New Tab") { ... }
} else {
Button("Open") { ... }
Menu("Open With") { ... }
}
}
Section {
Button("Move to Trash") { ... }
}
Section {
Button("Get Info") { ... }
Button("Rename") { ... }
if url.pathExtension != "zip" {
Button("Compress “\(url.lastPathComponent)”") { ... }
}
// ...
}
}
}
// In the toolbar setup:
let popUpButton = NSPopUpButton(frame: .zero, pullsDown: true)
(popUpButton.cell as! NSPopUpButtonCell).usesItemFromMenu = false
popUpButton.menu = NSHostingMenu(rootView: Group {
Button("New Folder") { ... }
FileOrFolderContextMenu(url: selectedURL)
})
// In the column view:
List(directoryContents, selection: $selection) { entry in
DirectoryEntryRow(entry: entry)
.contextMenu {
FileOrFolderContextMenu(url: entry.url)
}
}