How do you correctly use a SwiftUI View inside an NSToolbarItem?

I've been struggling to get consistent UI and UX behaviour of SwiftUI Views inside NSToolbarItems and was wondering if there is an official way to use them.

I've now revisited this issue in macOS 27 and continue to see some idiosyncrasies. In the attached screenshot, you can see that the highlight area on mouse down between to the two buttons is different. This is the easiest example I've come up with that shows SwiftUI Views exhibiting different behaviour than AppKit Views.

Two questions:

  1. Is an NSHostingView a valid and supported view type for NSToolbarItem.view?
  2. If so, are there any rules that govern how the SwiftUI view should be configured? (ex: frame, sizing options, supported SwiftUI Views, preferred "root view" types, etc?)

Sample code that created the two NSToolbarItem buttons in the screenshot.

  • macOS 27 ZY21R0CMGL (Public Beta 1)
  • Xcode 27.0 beta
  • Minimum Deployment target: 27.0
// Left-Top SwiftUI Button (Clipped Highlighting)
let item = NSToolbarItem(itemIdentifier: itemIdentifier)
let rootView = Button { } label: { Image(systemName: "sidebar.trailing") }
item.view = NSHostingView(rootView: rootView)

// ... snip .. 

// Right-Bottom AppKit Button (Correct Highlighting)
let item = NSToolbarItem(itemIdentifier: itemIdentifier)
item.image = NSImage(systemSymbolName: "sidebar.trailing", accessibilityDescription: nil)

Both screenshots are taken on mouse down.

NSToolbarItem manages its own style when isBordered is set to true (for example in your code is not manually adding a NSButton subview).

On the other hand, your SwiftUI code is manually adding a Button instead, and probably NSToolbarItem isn't smart enough to recognise the pattern and fall back to its internal NSButton subclass.

I don't know if there is a workaround, I would send a feedback of the issue and keep avoid NSHostingView for simple toolbar buttons, it doesn't like there isn't any advantage in SwiftUI for such things anyway.

@galad87

In this example, the benefits of a SwiftUI Button is minimal, but not zero. Integration with an existing @Observable view model, for example, is easier with a SwiftUI button versus the target/action pattern from AppKit.

Regardless, this snippet was more intended to show a minimal example I could come up with that exhibited differences between AppKit views and SwiftUI views within an NSToolbarItem.

As the complexity of the hosted SwiftUI view increases, the number of "glitches" I see increases. (ex: Window dragging that initiates inside the hosted SwiftUI view does not appear to work if that SwiftUI view has a subview with a gesture of its own. Mouse events appear to get consumed by the entire NSHostingView.)

Rich toolbar items like Safari's address bar or Xcode's status bar would be great candidates for SwiftUI, but my experience so far has been unsuccessful given the issues I've encountered embedding SwiftUI Views inside an NSToolbarItem.

I'm curious if these are known issues and this embedding isn't fully supported, or if I'm missing some rules and requirements I need to follow given NSToolbar's quirks.

How do you correctly use a SwiftUI View inside an NSToolbarItem?
 
 
Q