Using SwiftUI to Build a Mac-assed App in 2026 - Paulo's Blog
I recently launched the macOS version of Shopie, an app I first released on the iOS App Store late last year. Shopie helps you keep track of products you're interested in by letting you create wishlists and notifying you whenever a product's price, availability, and other details change.
Unlike my other apps, where I typically blend AppKit (or UIKit) with SwiftUI, Shopie is built entirely in SwiftUI. I wanted to keep it that way to maximize code reuse across iOS, iPadOS, and now macOS. This post explores how far SwiftUI can take you on the Mac in 2026, especially if your goal is to build an app that feels truly native to the platform. It's not meant to be an exhaustive review of SwiftUI on macOS. It's simply a collection of recipes and issues I ran into while porting Shopie, a fairly small app, and keeping it 100% SwiftUI.
If you want the TL;DR: we're not there yet.
What's a Mac-assed app?
The term "Mac-assed app" was coined by Collin Donnell and popularized by Brent Simmons and John Gruber. It describes apps that are not only native, but that also adopt the system's controls and conventions and integrate impeccably with the operating system's features.
I consider Secrets to be a Mac-assed app, and proudly so. It uses native controls and looks beautiful while doing so. It leans heavily on the menu bar, includes plenty of keyboard shortcuts, supports multiple windows, has tooltips and hover states, and adopts system technologies such as Password AutoFill, AppleScript (to control other apps), Safari app extensions, and sudden termination.
If you're a long-time Mac user, you can just feel it when an app ticks these boxes. But the popularity of Electron-based apps, and even the standard set by many first-party apps, may make this much harder for newer users to understand.
SwiftUI shortcomings on macOS
While porting Shopie to macOS, I ran into a spectrum of problems: from "this should be easier" to "this is simply not possible."
Selected states
On the Mac, selection has nuance. An item can be selected in an inactive window, selected but in a view that no longer has focus, or not selected at all and still be the current context menu target. SwiftUI handles some of this well, some of it awkwardly, and some of it not at all.
Inactive windows
The current HIG says inactive windows should "appear subdued and seem visually farther away than the main and key windows." Long-time Mac users know that usually means something more specific. Older versions of the HIG spelled this out explicitly: "only the controls of the key window have color."
Active versus inactive windows in the Finder
Ignoring this is often the first tell that an app was made with Electron. Visual Studio Code, where I'm writing this, doesn't follow this convention.
This part is actually fine in SwiftUI. Just like in AppKit, many system controls such as List and Button get it automatically, and custom controls can do the same by checking \.appearsActive ↗︎.
Selected but not focused
Next comes the case where an item is still selected, but its view is no longer focused.
De-emphasized selection in Mail
This matters because focus tells the user which part of the UI will respond to keyboard input. In the screenshot above, an email is selected but the containing list is not focused, so pressing the arrow keys won't move that selection.
AppKit has a built-in answer here: NSTableRowView exposes isEmphasized ↗︎, which lets you adjust the selection appearance when focus moves elsewhere.
In SwiftUI, if you're building your own list with ScrollView and LazyVStack instead of using List, you can achieve the same behavior by tracking the scroll view's focus state and passing that down through the environment.
ScrollView {<br>LazyVStack {<br>// content<br>.focusable(true)<br>.focused($isScrollViewFocused)<br>.environment(\.isEmphasized, isScrollViewFocused)
The rows can then read both \.isEmphasized and \.appearsActive and adjust their selection styling accordingly.
Context menu targets
The impossible case is context menus. In a proper Mac-assed app, opening a context menu should enable a focus ring around the item the menu applies to, even when that item isn't selected.
Context menu target versus selection in Reminders on macOS
In the screenshot above, the menu applies to the "Shopping" list even though "Reminders" is still selected, and the UI makes that distinction clear.
Context menu target versus selection in Stocks on macOS
In Stocks, for example, the menu applies to "AAPL" rather than the currently selected "MSFT" stock, but the interface doesn't communicate that.
The Notes app goes a step further in the wrong direction: right-clicking an unselected note immediately changes the selection. That is very much not a Mac-assed behavior 😪.
Reminders, Notes, and Stocks are all SwiftUI apps on macOS, yet each behaves differently. Reminders only gets this right because it's using List, which...