Back to Blog

Building a Floating Toolbar in SwiftUI for macOS - Lessons from a Desktop Agent

Fazm Team··3 min read
swiftuimacostoolbarui-designmenu-bar

Building a Floating Toolbar in SwiftUI for macOS

Building a floating toolbar that feels native on macOS is harder than it looks. Apple Notes, Xcode, and Spotlight all have floating panels with smooth animations and correct behavior around fullscreen apps, multiple displays, and keyboard shortcuts. Getting there with SwiftUI requires solving a few specific problems.

Window Configuration

The foundation is an NSPanel subclass rather than a regular NSWindow. Panels have the right default behavior for floating UI - they do not appear in the window switcher, they can float above other windows, and they handle focus correctly.

Key settings:

  • styleMask includes .nonactivatingPanel so clicking the toolbar does not steal focus from the active app
  • level set to .floating keeps it above regular windows
  • collectionBehavior includes .canJoinAllSpaces and .fullScreenAuxiliary for proper multi-desktop and fullscreen behavior

Layout With @State

The toolbar needs to track its own size because SwiftUI does not give you a reliable way to measure content after layout. Use a GeometryReader inside the toolbar content to report the size back to an @State property, then apply that size as the frame of the hosting window.

This creates a feedback loop - content determines window size, which determines available space. Break the loop by using .fixedSize() on the toolbar content so it always reports its intrinsic size rather than expanding to fill available space.

Smooth Expand and Collapse

When the toolbar expands (showing additional controls) or collapses, animate both the SwiftUI content and the window frame together. Use withAnimation for the content and NSAnimationContext for the window frame, matching the duration and timing curve.

The trick is animating the window frame from the correct anchor point. If your toolbar is pinned to the top of the screen, the frame should grow downward. Calculate the new origin as currentOrigin.y - heightDelta and set the frame in the same animation block.

Keyboard Height Tracking

If the toolbar includes a text field, the macOS virtual keyboard (on iPads connected to a Mac or accessibility keyboards) can overlap it. Listen for NSApplication.didChangeScreenParametersNotification and adjust the toolbar position when the available screen area changes.

These patterns combine into a floating toolbar that feels like a native macOS component rather than a web-style overlay.

Fazm is an open source macOS AI agent. Open source on GitHub.

Related

Related Posts