Connor Holly

← AI Skills

SwiftUI Menu Bar Apps

Developer Tools

swiftmacosnative

A pattern for building lightweight native macOS menu bar utilities with SwiftUI — no window, no dock icon, just a persistent status item that runs background logic and surfaces information on demand.

The Pattern

The app structure is minimal. No WindowGroup, no main window. Just a MenuBarExtra that lives in the system tray.

@main
struct MyMenuBarApp: App {
    var body: some Scene {
        MenuBarExtra("App Name", systemImage: "icon.name") {
            ContentView()
        }
    }
}

From this skeleton, four capabilities cover most menu bar use cases:

System event monitoring. Watch for app activations, display sleep/wake, workspace changes via NSWorkspace.shared.notificationCenter. Monitor keyboard and mouse globally with NSEvent.addGlobalMonitorForEvents. This is how you build time trackers, focus monitors, and activity loggers.

Periodic data fetching. Timer.scheduledTimer for polling APIs, checking file changes, or updating displayed metrics. URLSession for HTTP calls. Parse JSON responses and update SwiftUI state with @Published properties on an ObservableObject.

Local persistence. UserDefaults for simple key-value state. @AppStorage for SwiftUI-reactive bindings to UserDefaults. For anything more complex, write JSON files to the app's container directory.

System integration. NSAppleScript bridges to control other apps (Spotify, browsers, system preferences). SMAppService.mainApp.register() for launch-at-login. NSPasteboard for clipboard access.

Key Decisions

Menu bar only, no dock icon. Set LSUIElement = true in Info.plist. The app runs as a background agent — no dock presence, no Cmd-Tab entry. Users interact exclusively through the menu bar popover.

SwiftUI over AppKit. MenuBarExtra is SwiftUI-native since macOS 13. For simple popovers with lists, buttons, and text, SwiftUI is dramatically less code than NSMenu + NSStatusItem. Drop to AppKit only for system APIs that SwiftUI doesn't wrap.

Local code signing. codesign --force --deep --sign - is sufficient for personal-use apps that won't be distributed. Skip the Apple Developer Program unless you need notarization for distribution.

Build pipeline. swift build -c release produces a binary. Wrap it in a .app bundle with a minimal Info.plist for Finder integration and launch-at-login support. No Xcode project required — a Package.swift file is enough.

When to Use It

Ambient information display (build status, stock prices, weather, system metrics), background automation (time tracking, file watching, periodic syncs), or system integration utilities (clipboard managers, quick-launch tools). Anywhere you want persistent, lightweight functionality without a full app window. The sweet spot is apps with a 5-second interaction model: glance, maybe click one thing, move on.