By Rajeev Ranjan · 21 Jul 2026
Building a macOS Menu Bar App with SwiftUI: A Complete Guide
Everyone loves a good menu bar app. It sits quietly in the top-right corner of your Mac, always a click away a clipboard manager, a weather glance, a system monitor. They feel simple, but building one well requires understanding a few non-obvious patterns.
In this guide, I'll walk through everything I've learned building ShiftOS, a full menu bar suite with window management, clipboard history, and system control and distill it into a practical tutorial.
Starting Point: MenuBarExtra
Starting with macOS 13 (Ventura), Apple introduced MenuBarExtra — a SwiftUI-native way to create menu bar apps without AppKit. Before this, you needed an NSStatusItem and an NSMenu. Now it's a few lines.
import SwiftUI
@main
struct MyMenuBarApp: App {
var body: some Scene {
MenuBarExtra("My App", systemImage: "star.fill") {
ContentView()
}
}
}That's it. You now have a menu bar app. The systemImage becomes your icon, and the trailing closure is your menu content.
The Critical Detail: Keeping the App Alive
Newcomers often wonder why their menu bar app quits when they close the settings window. The answer: your App scene needs both a MenuBarExtra and a Settings scene — but never a WindowGroup unless you intend a regular window.
@main
struct MyMenuBarApp: App {
var body: some Scene {
MenuBarExtra("My App", systemImage: "star.fill") {
ContentView()
}
.menuBarExtraStyle(.menu)
Settings {
SettingsView()
}
}
}Building the Menu Content
A menu bar app's content should be compact. Users expect to get in and out quickly.
struct ContentView: View {
@State private var items = ["Item 1", "Item 2", "Item 3"]
var body: some View {
VStack(alignment: .leading, spacing: 0) {
ForEach(items, id: \.self) { item in
Text(item)
.padding(.horizontal, 12)
.padding(.vertical, 6)
}
Divider()
Button("Quit") { NSApplication.shared.terminate(nil) }
.keyboardShortcut("q")
}
.frame(width: 220)
}
}Two MenuBarExtra Styles
.menu— Classic NSMenu look, good for simple lists with highlight-on-hover.window— Presents a custom SwiftUI view in a popover window, essential for complex UI (search bars, settings toggles, grid layouts)
ShiftOS uses .window for its Clipboard panel because we need a search field and inline markdown rendering inside a scrollable container.
Where Menu Bar Apps Break
A few gotchas I've hit building production menu bar apps:
- Window focus: When your
.windowpopover opens, the parent app loses focus. Handle this gracefully — don't rely onNSApp.activate()unless necessary. - Keyboard shortcuts: Menu bar apps can conflict with system shortcuts. Use
CGEventflags to check if a shortcut should be intercepted, and provide a conflict resolver (ShiftOS has a full Shortcut Inspector for this). - Memory: Menu bar apps stay running. Profile with Instruments. A leak that would go unnoticed in a regular app becomes a visible problem when your app has been running for two weeks.
- ScreenCaptureKit permissions: If your app shows window previews (like ShiftOS SwitchTab), users must grant Screen Recording permission. Detect this state and show a clear setup guide.
A Practical Template
Here's a production-ready starter I wish I had when I began:
import SwiftUI
@main
struct CompactMenuBarApp: App {
@StateObject private var engine = AppEngine()
var body: some Scene {
MenuBarExtra {
AppMenuView()
.environmentObject(engine)
}
.menuBarExtraStyle(.window)
Settings {
SettingsView()
.environmentObject(engine)
}
}
}
@MainActor
final class AppEngine: ObservableObject {
@Published var isActive = false
// Business logic lives here, not in views
}Publishing to the Mac App Store
Menu bar apps have specific requirements:
- Set
LSUIElementtotruein Info.plist — this hides the Dock icon and menu bar - Provide a reasonable menu bar icon (16x16 template image, or use SF Symbols)
- Test that your app survives a logout/login cycle
Final Thoughts
Menu bar apps are deceptive. They look simple but demand attention to detail in areas most apps never touch: persistence, system integration, memory management, and graceful permission handling. But when done right, they become the kind of tool users recommend to others.
ShiftOS started as a single menu bar utility. It grew into a suite. But the foundation is the same MenuBarExtra pattern I just showed you.