SwiftUI: how to add toolbar to a window for a macOS app?

billibala
2 min readApr 25, 2020

--

Toolbar is an essential UI component for Mac apps. SwiftUI, as of Xcode 11.4, however, does not provide a Toolbar View. So, what can we do?

In general, in macOS Catalina, SwiftUI provides all the components needed to build UI inside NSWindow’s content view. UI components outside of the content view relies on traditional AppKit to provide support.

Our solution here rides alone this line… We will be adding an NSToolbar object to NSWindow in code.

I’ve seen discussions which recommends using title bar accessory view as solution:

The proposed solution is quite nice. It’s simple and easy to setup.

But faking a toolbar doesn’t seem quite right to me. You lose all the perks (allowing user to customize the toolbar, Touch Bar support) AppKit gives to a real toolbar.

So, let’s use a real NSToolbar.

My solution here is based on Xcode’s macOS SwiftUI app template. The toolbar is created programmatically. No storyboard. No Xib.

Sample code is on Github — SUIToolbarPlay

In AppDelegate.swift, instantiate a NSToolbar object (static variable in this example).

When programmatically create NSToolbar object, you need to assign the toolbar object a delegate. In this example, we use AppDelegate as the delegate.

func applicationDidFinishLaunching(_ aNotification: Notification) {
// Create the SwiftUI view that provides the window contents.
let contentView = ContentView()

// Toolbar **needs** a delegate
NSToolbar.taskListToolbar.delegate = self
// Create the window and set the content view.
window = NSWindow(
contentRect: NSRect(x: 0, y: 0, width: 480, height: 300),
styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView],
backing: .buffered, defer: false)
window.center()
// Assign the toolbar to the window object
window.toolbar = .taskListToolbar
window.titleVisibility = .hidden
window.setFrameAutosaveName("Main Window")
window.contentView = NSHostingView(rootView: contentView)
window.makeKeyAndOrderFront(nil)
}

Check Toolbar.swift file. We extend AppDelegate to implement NSToolbarDelegate protocol.

`toolbarDefaultItemIdentifiers`, `toolbarAllowedItemIdentifiers` and `toolbar(_, itemForItemIdentifier:, willBeInsertedIntoToolbar:)` are the minimum set of methods you need to implement.

To get a better idea, please try out the sample code.

You can also find the list of resources which I find useful during my research and preparation of the sample code.

--

--

billibala
billibala

Written by billibala

Indie developer on everything Apple — macOS, iOS, watchOS, etc. I build great apps: Sched, Eventbrite, Eventbrite Organizer (Neon). Ping me for projects.

Responses (1)