Michael Tsai - Blog - Building Shopie for Mac With SwiftUI

9 min read Original article ↗

Paulo Andrade (Mastodon):

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.

[…]

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. […] 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 inherits the behavior from NSTableView.

[…]

SwiftUI has already gone through three drag-and-drop eras. […] But the problem with all three is that you have no visibility into the drag session unless you are the drop target.

[…]

Once again, the issue isn’t that keyboard support is impossible in SwiftUI. It’s that the framework gives you just enough to cover the simple cases, then gets in your way the moment you try to match what Mac apps have done for decades.

David Deller:

Spent most of the day fighting with SwiftUI and getting nowhere. Hate it when this happens. The solution, as always, was to redo some parts in AppKit. I wish I had done this whole app in AppKit from the start.

SwiftUI never gave me this much trouble on iOS, but it’s so much worse on Mac. And context-switching between the two is a drag.

Patrick McConnell:

SwiftUI is littered with things that do 85% of what you need and then get ignored for years. It’s the iPadOS of frameworks.

Yes, we can use Cocoa frameworks (and I do) but why can’t SwiftUI approach the level of the Cocoa frameworks?

I think in many cases Cocoa is more effective simply because Apple hasn’t spent the effort to bring SwiftUI to the same level.

Helge Heß:

I think it’s because SwiftUI is not intended to be a Cocoa level framework. Similar in how Objective-C is not supposed to replace C. That would be Smalltalk, which shows how impractical (however nice) that would be.

My personal suggestion is to consider SwiftUI a form builder on steroids. It’s extraordinarily effective for things builtin.

Helge Heß:

I can’t tell what their long-term plan is, but IMO it’s extremely unlikely to be a fully SwiftUI based system. Except for tiny platforms like watchOS (the original target AFAIK). I suspect that SwiftUI for UIKit+ was never intended to be a competitor to Cocoa, but to ReactNative and the likes.

Colin Cornaby:

I had the unpleasant experience of trying to do something complicated with a scroll view in SwiftUI. You can’t get or manipulate the scroll offset directly? What?

Previously:

Update (2026-05-11): Max Seelemann:

Couldn’t have said it better.

Louie Mantia:

Every macOS developer comes to the same conclusion after trying to use SwiftUI to make a proper Mac app: it’s not ready (yet).

To be honest, I can’t understand why everyone keeps trying.

Regarding the scrolling limitation that Cornaby mentioned, Fatbobman writes:

This article will explore these latest scroll control APIs and review the development of all significant APIs related to scroll control since the inception of SwiftUI.

See also Phil Zakharchenko.

Michele:

As usual, it only works for the simple case, just try to add Section to your List and it breaks.

Phil Zakharchenko:

While trying out a few things around the SwiftUI document handling and lifecycle in a macOS application, I came across a pretty bad issue. Not only did it not do as the API promised, it actually messed with the menu in ways that would be unrecoverable to a SwiftUI lifecycle application.

Steve Troughton-Smith:

I maintain building SwiftUI instead of working on a true AppKit/UIKit replacement was a generational mistake — 7 years later we’re back where we started, unable to trust SwiftUI to build a platform around, still in need of a modern, more-powerful and dependable UI framework that spans all the way down, and up, Apple’s product line. SwiftUI, outside of watchOS, gained us absolutely nothing of value, and has eroded a lot of the software quality we once took for granted

(Could you have done [a more pared-back] SwiftUI and a next-gen framework, absolutely! SwiftUI should never have been load-bearing.)

Alex Rosenberg:

I’m mostly disappointed that none of the newer frameworks have the sophistication of NSTableView and all the column rearranging and whatnot.

Dominik Wagner:

I could not agree more. It is no coincidence that there has been almost no major new mac-assed mac app since this shift inside apple. I was there when it happened, and sadly could not stop it.

The saddest thing is that a lot of apple also agreed that this was the wrong way, but politics and pro swift timelines did just dismiss all of these. Much to the detriment to what, at least to me, made apple apple, besides all its flaws: a strive to great user interaction.

Marco Arment:

I really like SwiftUI.

It just still has a lot of missing or incomplete functionality, and Apple doesn’t seem to be in much of a rush to fill in the gaps.

I sometimes wonder how much better macOS could be today if they’d never tried to make the iPad into a Mac replacement, and had focused on maintaining and improving just one great PC-class OS.

Dennis Oberhoff:

SwiftUI Previews are pretty cool. I think the biggest problem that people struggle with it is that their dependency graph is missing when they pull it up.

It crashes and its very bad in telling you why.

Helge Heß:

I think a reason why todays Apple frameworks (and languages) have “issues” is that they are being build as frameworks by framework teams, not as part of apps to support the apps, such are supposed to follow. This used to be different. AppKit was built to support creating great new apps very quickly for the NeXT, which needed apps from scratch, to be developed by NeXT themselves. Mail, Preview, Workspace, Chess, etc the minimum to get working.

Same for UIKit which wasn’t even originally meant for public consumption (which shows). It was created to quickly build good first party apps.

I’m not entirely sure, but I think this is different for SwiftUI (and many other Apple frameworks). Maybe it was the original intention for watchOS, but certainly not for UIKit+. It doesn’t seem it was “app first”. (even just for something seemingly simple/baseline, like building TextEdit or Finder)

I recall the SwiftUI team saying that during the design phase they wanted to make sure that it was capable of building Keynote. But it doesn’t look like they actually rebuilt Keynote using SwiftUI, the way Finder was rewritten from Carbon to Cocoa. My copy of Keynote for Mac has 373 nib files. So much of the story of modern APIs (not just SwiftUI) is the difference between what they can do on paper vs. in practice.

Update (2026-05-12): Keren R. Bell:

There’s a few elements to this app that I couldn’t add easily with SwiftUI, and after consulting the usual suspects, it seems I couldn’t. Take the menu bar, part of the Mac’s identity. Despite various articles promising customizability, you can’t actually tailor it to fit your app without nuking it and starting from scratch.

[…]

There’s a few other things. SwiftUI basically can not talk to the clipboard. […] To implement moving points on the canvas with Arrow keys, I couldn’t just assign the function a a keyboard shortcut. My current embarassing solution is invisible, 0x0 accessibility-hidden buttons behind the canvas, with a modifier-less Keyboard Shortcut attached to each.

Helge Heß:

People often complain about some SwiftUI bugs, lack of feature XYZ and such. But I think they often miss the structurally deep / conceptual issues. Like how many instance methods does View have? Something like 500+?

David Beck:

Agreed. Some of them apply to one specific view type, but are hard to find because they exist in this soup. Some apply to multiple types of views, but have slightly different effects. And sometimes, different views will have different modifiers to do the same thing.

It’s basically subverting the type system. Also, instead of literate APIs it relies on implicit stuff like this:

At this point, AppKit developers with their finger on the pulse may be familiar with setting subtitles on NSMenuItem using the subtitle property, which has been available since macOS 14.4.

[…]

The key insight is that we can use multiple Text views within a Button’s label to force SwiftUI to interpret the first Text view as a title, and the second one as a subtitle.

Update (2026-05-19): Natalia Panferova:

In this post we will explore the most modern APIs that SwiftUI provides for programmatic scrolling, covering how to configure the initial scroll position of a scroll view, how to drive it programmatically, and how to read the current position back. We will also cover some of the nuances that are easy to miss. It's worth noting though, that all of these new APIs apply to ScrollView only, and ScrollViewReader remains the only native option for programmatic scrolling in lists.

Update (2026-05-21): Collin Donnell:

If you were building a new Mac app today, how would you structure it? My feeling is still AppKit skeleton/lifecycle with SwiftUI views mixed in as much as possible.

20 Comments