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:

  1. Window focus: When your .window popover opens, the parent app loses focus. Handle this gracefully — don't rely on NSApp.activate() unless necessary.
  2. 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).
  3. 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.
  4. 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 LSUIElement to true in 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.

macOS menu bar app SwiftUIbuild mac menu bar appSwiftUI MenuBarExtra tutorial