# How to Integrate SwiftUI with CodexBar's Menu Bar: A Complete Guide

> Learn to integrate SwiftUI with CodexBar's menu bar using NSHostingView and StatusItemController. This guide simplifies bridging AppKit and SwiftUI for a seamless menu bar experience.

- Repository: [Peter Steinberger/CodexBar](https://github.com/steipete/CodexBar)
- Tags: how-to-guide
- Published: 2026-07-07

---

**Integrating SwiftUI with CodexBar requires bridging AppKit's `NSStatusItem` and `NSMenu` with SwiftUI views using `NSHostingView`, coordinated through the `StatusItemController` class that manages the menu bar lifecycle and rendering.**

CodexBar is a macOS menu bar application that mixes classic AppKit components with modern SwiftUI to render rich, data-driven pop-over content. The integration leverages specific coordinator classes and extension files to embed declarative SwiftUI views within the imperative AppKit menu hierarchy, allowing for complex UI like usage charts and custom cards while maintaining native status bar behavior.

## Understanding the Architecture

CodexBar employs a hybrid architecture where the status bar icon and menu shell use AppKit, while the content cards use SwiftUI. This approach centers on the `StatusItemController` class, which acts as the bridge between the two frameworks.

The core components include:

- **`StatusItemController`** – Creates the `NSStatusItem`, manages the `NSMenu` lifecycle, and coordinates refresh cycles.
- **`MenuCardRefreshMonitor`** – A lightweight observer that triggers SwiftUI view updates when underlying data changes.
- **`NSHostingView`** – The standard SwiftUI mechanism for embedding SwiftUI views into AppKit hierarchies, used extensively throughout the menu building process.

## The Integration Flow

### StatusItemController as the Coordinator

In [`Sources/CodexBar/StatusItemController.swift`](https://github.com/steipete/CodexBar/blob/main/Sources/CodexBar/StatusItemController.swift), the `StatusItemController` class initializes the menu bar presence via `makeStatusItem()` and attaches menus through `attachMenus()`. This class also owns a `MenuCardRefreshMonitor` (defined at lines 20–22) that watches for data changes and invalidates the menu when updates occur.

When a user clicks the status item, the controller builds the menu dynamically rather than using static `NSMenuItem` instances.

### Embedding SwiftUI via NSHostingView

The bridging logic resides in `Sources/CodexBar/StatusItemController+Menu.swift`. The `makeMenu(for:)` method constructs an `NSMenu` instance and calls `menuCardModel(for:)`, which returns an `AnyView` representing the SwiftUI content. This view is then wrapped in an `NSHostingView` and inserted into the menu hierarchy.

### Menu Item Creation

In `Sources/CodexBar/StatusItemController+MenuCardItems.swift`, the `makeMenuCardItem()` function creates a standard `NSMenuItem` and sets its view to an `NSHostingView(rootView: <Your SwiftUI View>)`. This final step embeds the SwiftUI content into the AppKit menu, allowing it to render alongside traditional menu items.

## Step-by-Step Implementation Guide

### Create Your SwiftUI View

Define a lightweight SwiftUI view that conforms to the `View` protocol. The view should be stateless or use observed objects for data, as it is reinstantiated each time the menu rebuilds.

```swift
import SwiftUI

struct MyCustomCard: View {
    let title: String
    let value: String

    var body: some View {
        VStack(alignment: .leading, spacing: 4) {
            Text(title).font(.headline)
            Text(value).font(.title).foregroundColor(.accentColor)
        }
        .padding(8)
    }
}

```

### Expose a Factory Method in the Provider

Extend your provider implementation (e.g., `CodexProviderImplementation`) to expose a method that returns `AnyView`. This factory method instantiates your SwiftUI view with the appropriate data.

```swift
extension CodexProviderImplementation {
    func makeMyCustomCard() -> AnyView {
        AnyView(MyCustomCard(title: "My Metric", value: "42 pts"))
    }
}

```

### Wire the View into StatusItemController

Update the `menuCardModel(for:)` method in `Sources/CodexBar/StatusItemController+Menu.swift` to return your new view when the appropriate provider is active.

```swift
private func menuCardModel(for provider: UsageProvider) -> AnyView {
    switch provider {
    case .codex:
        return CodexProviderImplementation.shared.makeMyCustomCard()
    // ... existing cases ...
    }
}

```

### Handle Data Updates

If your view depends on dynamic data, ensure the provider stores the necessary keys so that `MenuCardRefreshMonitor` detects changes. When data updates, the monitor calls `invalidateMenus(refreshOpenMenus: true)`, triggering a rebuild of the SwiftUI view so the pop-over reflects the latest state.

## Complete Code Example: Adding a Build Counter Card

The following example demonstrates adding a "Build Counter" card to the CodexBar menu.

First, create the SwiftUI view in [`Sources/CodexBar/BuildCounterCard.swift`](https://github.com/steipete/CodexBar/blob/main/Sources/CodexBar/BuildCounterCard.swift):

```swift
import SwiftUI

struct BuildCounterCard: View {
    let builds: Int

    var body: some View {
        HStack {
            Image(systemName: "hammer")
            Text("\(builds) builds this session")
        }
        .padding(.horizontal, 10)
        .padding(.vertical, 6)
    }
}

```

Next, extend the provider in [`Sources/CodexBar/Providers/Codex/CodexProviderImplementation.swift`](https://github.com/steipete/CodexBar/blob/main/Sources/CodexBar/Providers/Codex/CodexProviderImplementation.swift):

```swift
extension CodexProviderImplementation {
    func makeBuildCounterCard() -> AnyView {
        // Assume `store` offers `sessionBuildCount`
        AnyView(BuildCounterCard(builds: store.sessionBuildCount))
    }
}

```

Finally, wire the card into the controller in `Sources/CodexBar/StatusItemController+Menu.swift`:

```swift
private func menuCardModel(for provider: UsageProvider) -> AnyView {
    switch provider {
    case .codex:
        // Existing Codex cards ...
        return CodexProviderImplementation.shared.makeBuildCounterCard()
    // other providers ...
    }
}

```

When users click the CodexBar icon, the pop-over now displays the **Build Counter** card alongside existing usage charts. The `MenuCardRefreshMonitor` automatically refreshes this card whenever `sessionBuildCount` changes.

## Key Files and Their Roles

- **[`Sources/CodexBar/StatusItemController.swift`](https://github.com/steipete/CodexBar/blob/main/Sources/CodexBar/StatusItemController.swift)** – Central coordinator that creates status items, attaches menus, and drives the refresh cycle via `MenuCardRefreshMonitor`.
- **`Sources/CodexBar/StatusItemController+Menu.swift`** – Contains `makeMenu(for:)` and `menuCardModel(for:)` methods that build `NSMenu` instances and embed SwiftUI views.
- **`Sources/CodexBar/StatusItemController+MenuCardItems.swift`** – Defines `makeMenuCardItem()` which wraps SwiftUI views in `NSHostingView` and attaches them to `NSMenuItem` instances.
- **[`Sources/CodexBar/UsageMenuCardHeaderAndUsageSectionView.swift`](https://github.com/steipete/CodexBar/blob/main/Sources/CodexBar/UsageMenuCardHeaderAndUsageSectionView.swift)** – Example SwiftUI view demonstrating usage data presentation in the menu pop-over.
- **`Sources/CodexBar/Providers/*/*ProviderImplementation.swift`** – Provider-specific logic where you add factory methods returning custom SwiftUI cards.

## Summary

- **Use `NSHostingView`** to embed SwiftUI views into AppKit's `NSMenu` hierarchy.
- **Modify `StatusItemController`** in `Sources/CodexBar/StatusItemController+Menu.swift` to return your SwiftUI view from `menuCardModel(for:)`.
- **Extend provider implementations** to expose factory methods that create `AnyView` instances, keeping view creation logic decoupled from the controller.
- **Leverage `MenuCardRefreshMonitor`** to automatically update SwiftUI content when underlying data changes, ensuring the menu bar UI stays synchronized with application state.
- **Keep SwiftUI views lightweight** because they are reinstantiated each time the menu rebuilds.

## Frequently Asked Questions

### How does CodexBar bridge SwiftUI with NSMenu?

CodexBar uses `NSHostingView` from SwiftUI to wrap SwiftUI views and embed them as the view property of `NSMenuItem` instances. The `StatusItemController` class manages this process through `makeMenuCardItem()` in `Sources/CodexBar/StatusItemController+MenuCardItems.swift`, creating a seamless bridge between AppKit's menu system and SwiftUI's declarative interface.

### Where do I add custom SwiftUI views in the codebase?

Create your SwiftUI view files in `Sources/CodexBar/`, then extend the appropriate provider implementation (such as `CodexProviderImplementation`) to expose a factory method returning `AnyView`. Finally, update the `menuCardModel(for:)` method in `Sources/CodexBar/StatusItemController+Menu.swift` to include your new view in the switch statement that handles different providers.

### How does the menu refresh when data changes?

The `MenuCardRefreshMonitor` (defined at lines 20–22 of [`StatusItemController.swift`](https://github.com/steipete/CodexBar/blob/main/StatusItemController.swift)) observes relevant data stores. When it detects changes, it calls `invalidateMenus(refreshOpenMenus: true)`, which triggers a rebuild of the menu and reinstantiates the SwiftUI views with updated data, ensuring the pop-over content remains current.

### Can I use any SwiftUI view in the menu bar?

Yes, you can embed any SwiftUI view that conforms to the `View` protocol, provided you wrap it in `AnyView` and embed it via `NSHostingView`. However, avoid views with complex animations or heavy state management, as the views are recreated each time the menu opens. Stick to lightweight, data-driven presentations for optimal performance in the menu bar environment.