How to create status bar icon & menu with SwiftUI like in macos Big Sur

Since this question got more attention lately and the only reply doesn't fully solve the issue I would like to repeat the edited part of my question and mark it as resolved.

Found a way to show swiftui without annoying NSPopover. You'd need to have 'AppDelegate' or 'NSApplicationDelegateAdaptor' in case you use SwiftUI App lifecycle. Then you create NSMenu and add NSMenuItem that can have a custom view.

Here is the code:

    let contentView = VStack {
        Text("Test Text")
        Spacer()
        HStack {
            Text("Test Text")
            Text("Test Text")
        }
        Spacer()
        Text("Test Text")
    }
    let view = NSHostingView(rootView: contentView)
    // Don't forget to set the frame, otherwise it won't be shown.
    view.frame = NSRect(x: 0, y: 0, width: 200, height: 200)
    
    let menuItem = NSMenuItem()
    menuItem.view = view
    
    let menu = NSMenu()
    menu.addItem(menuItem)
    
    // StatusItem is stored as a class property.
    self.statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
    self.statusItem?.menu = menu
    self.statusItem?.button?.title = "Test"

enter image description here


Inside the AppDelegate add the following code:

// Create the status item in the Menu bar 
self.statusBarItem = NSStatusBar.system.statusItem(withLength: CGFloat(NSStatusItem.variableLength))

// Add a menu and a menu item
let menu = NSMenu()
let editMenuItem = NSMenuItem()
editMenuItem.title = "Edit"
menu.addItem(editMenuItem)

//Set the menu 
self.statusBarItem.menu = menu

//This is the button which appears in the Status bar
if let button = self.statusBarItem.button {
    button.title = "Here"
}

This will add a Button with a custom Menu to your MenuBar.

enter image description here

Edit - How to use SwiftUI View

As you asked, here is the answer how to use a SwiftUI View.

First create a NSPopover and then wrap your SwiftUI view inside a NSHostingController.

var popover: NSPopover


let popover = NSPopover()
popover.contentSize = NSSize(width: 350, height: 350)
popover.behavior = .transient
popover.contentViewController = NSHostingController(rootView: contentView)
    self.popover = popover

Then instead of showing a NSMenu, toggle the popover:

self.statusBarItem = NSStatusBar.system.statusItem(withLength: CGFloat(NSStatusItem.variableLength))
if let button = self.statusBarItem.button {
     button.title = "Click"
     button.action = #selector(showPopover(_:))
}

With following action:

@objc func showPopover(_ sender: AnyObject?) {
    if let button = self.statusBarItem.button
    {
        if self.popover.isShown {
            self.popover.performClose(sender)
        } else {
            self.popover.show(relativeTo: button.bounds, of: button, preferredEdge: NSRectEdge.minY)
        }
    }
}

enter image description here