Building Shopie for Mac With SwiftUI
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 fromNSTableView.[…]
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.
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.
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.
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.
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.
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.
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.
As usual, it only works for the simple case, just try to add
Sectionto yourListand it breaks.
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.
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.)
I’m mostly disappointed that none of the newer frameworks have the sophistication of
NSTableViewand all the column rearranging and whatnot.
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.
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.
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.
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.
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
Viewhave? Something like 500+?
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
NSMenuItemusing thesubtitleproperty, which has been available since macOS 14.4.[…]
The key insight is that we can use multiple
Textviews within aButton’s label to force SwiftUI to interpret the firstTextview 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
ScrollViewonly, andScrollViewReaderremains 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 RSS · Twitter · Mastodon
Yes yes it still sucks after all these years but just keep using it fellas because it’s “the future” as proclaimed by the Schaeff
At this point I think we have to assume that it can’t be fixed. Software version of the trash can Mac Pro… they painted themselves in a corner. Time to tap out. Say Uncle
The bit about drag and drop is painfully real - I wrote a little Fluid-like thing, and it took me several days to figure out why drag-and-drop stopped working out of the blue
I can only look at it with a bird eye's perspective, but I think
* if SwiftUI didn't have its own app lifecycle
* nor its own concepts of documents, etc.
* and Apple hadn't called it "the future of apps" or something
then this would make perfect sense. Use SwiftUI for the bulk of UI scenarios, which aren't complex but plentiful. Benefit from previews and whathaveyou. Then, for the rare but complex UI that needs, say, "manipulate the scroll offset directly" (I imagine not only 90% of apps never need to do this, but also most scroll views _within_ apps where there _is_ that one view that needs to), you drop down to AppKit/UIKit.
Strategically, I think there were too many distractions. Instead of choosing between Catalyst, whatever "iPad on Mac" is supposed to be called, _and_ SwiftUI, Federighi picked _all three_. Instead of constraining SwiftUI to use cases where it's great, it has crept into all kinds of areas. It's still _way_ better than the Windows desktop UI strategy, if you can call it that, but it's also much muddier than a decade ago.
Re that final quote: https://mastodon.social/@colincornaby/116500881609373923
“Oh thanks. Thats what I was looking for. The chat bots said it was impossible!”
>I suspect that SwiftUI for UIKit+ was never intended to be a competitor to Cocoa
Hmm, yet AppKit has seen only tiny improvements in years. Like how Carbon stuck around for a while, but had only tiny improvements. I'm pretty sure AppKit is the new Carbon, and has been for years. When AppKit finally dies, I'm just leaving the platform.
@Nat as usual, it only works for the simple case, just try to add Section to your List and it breaks.
@Bob read the updates on the post here:
https://mjtsai.com/blog/2025/06/18/swiftui-at-wwdc-2025/
Slowly devs are turning on it.
Steve Troughton says SwiftUI is under fire from forces even inside Apple. Who knows what’s true but if it is that is great.
I don’t think SwiftUI is the future. I 100% KNOW SwiftUI is not my future. If they kill Appkit (don’t really see how they realistically can) i will pick a cross platform framework for app development and move on.
I’m not interested in being their puppet and engaging in yearly rewrites for the same features. I’ll just jump off the hamster wheel
I've found that SwiftUI also lives in a strange middle ground of not providing enough low-level access to advanced features to enable fully-featured solutions, and yet it doesn't also provide enough rich high-level components to easily deliver consistent platform native behaviour out-of-the-box.
A lot of the in-built views seem so inflexible that when you try to use them in an advanced manner you hit a wall that cannot be avoided. But if you want to create even simple things like a List View that looks like the Settings app on iOS, with the correct margins, styling, headers and behaviours it's more work than you'd expect. The in-built views also don't translate across-platforms well either: so something that may be ok on iOS won't work acceptably on macOS.
What this tends to mean is that you more often than not just end up creating a lot of custom views to do what you need and that work cross-platform instead of using the in-built views.
> Apple dropped the ball here. AppKit was ahead of its time and UIKit was a more polished version of AppKit. A serious cross-platform framework that unified the two should have happened long before SwiftUI. Instead, Apple left AppKit to fossilize and then tried to leapfrog the problem.
I actually rather thought that it was always UIKit that less polished, versus AppKit.
AppKit has baggage, sure, but it's clearly a system that is far more capable and flexible than what we've ever gotten with iOS - which is basically list-detail navigation, sometimes with a tab bar thrown in. Just look at the number of objects/widgets/view types you have available in Interface Builder, versus what's available for UIKit. It's been this way since 2008, nothing's changed. Hell, "iPadOS" didn't even change that, even if we do have a multi-window mode now.
Earlier versions of Xcode, around the v2 and v3 era, seemed like they were building towards a future where programming on Apple's platforms would be more approachable. These versions had tons of project templates and pre-made view types, ready by default. Somewhere along the line, that vision seems to have been forgotten.
Today I'm here to introduce three Apple technologies that were tried and killed before reaching 7 years of age:
- ObjC garbage collection (2 years). Bad fit that needed explicit code path and framework support.
- Cocoa Bindings (about 5 years). Stringly-typed, hard to debug.
- Java for Mac OS X (about 6 years). Slow, rendering glitches, inconsistent runtime behavior.
Bad fit. Hard to debug. Slow.
Bad fit. Weird typing. Glitchy rendering.
Bad fit. Unwieldy. Cross-platform inconsistency.
Are you getting it?
I'm not talking about three separate Apple technologies with various downsides. I'm talking about a single Apple technology with all of them: SwiftUI.
--
Chasing the React paradigm was wrong 7 years ago and it's even dumber today.
Outside of Swift itself, I've never seen a technology so unworthy of all the fawning and praise it has received.
Happy early 7th birthday FormBuilderUI! I hope you don't make it to 8.
Something I always pay attention to when considering any new format, media etc, is what do the tools used for it look like. What's the work methodology etc. Decades of print & multimedia design, I've been through just about every toolchain that's existed within those industries at various times, and the thing that always struck me about the developer tools Apple inherited from NeXT (AppKit), is how much they made building a UI look like working in Keynote (or Director), as compared to whenever I see people showing working in SwiftUI, it just looks like writing CSS as code.
Seems a step backwards to me.
"is how much they made building a UI look like working in Keynote (or Director), as compared to whenever I see people showing working in SwiftUI, it just looks like writing CSS as code."
That's due to the way software development has changed over the last 30 years. It used to be that you built software for one target platform that had quite well-known specifications. For example, every original NeXT computer had a monochrome display with a resolution of 1120 x 832 pixels, I believe. So it was fine to assume a minimum size for your UI and then add some affordances to let it grow if the user resized the window.
But if you make software today, it targets many different devices. Even if it's just Mac software, there are many different screens with different resolutions and different pixel densities. And maybe you also want to target mobile devices, like an iPad or iPhone, without designing completely different user interfaces.
That's the reasoning behind systems like SwiftUI: you don't make a pixel-perfect design; instead, you give your data and rules to a renderer, and it generates a UI that matches the user's device. It should be quite evident what the problem with this approach is: if you're not investing a huge amount of effort into building this in an extensible, flexible way, you're asking the developer to give up a lot of control over how their application renders and what it can do.
That doesn't necessarily mean that the idea is bad. It works well enough on the web. It's just that Apple sucks at giving up control, and if you're asking them to invest time and effort into making SwiftUI more flexible, and all they ostensibly get out of it is that they are surrendering control to developers, you know that it's going to be an uphill battle.
@Plume Yeah I understand that, what I was more getting at is the tools seems to have become less visual. I guess it's a larger issue within software - the likes of GoLive and Dreamweaver for web design, where you had powerful WYSIWYG editors, which also did powerful code editing. Now it seems all there is are code editors, that give you a live preview in a browser window, but they don't let you interact with the live viewer.
The irony of course being that most Swift and Catalyst apps are garbagefires when it comes to changing window sizes, or offering features like tear off palettes, or multiple document windows per app etc.
Personally I don't think it's a technology problem, I don't think it's the nature of deployment targets being more flexible, I think it's a cultural thing - the paradigm of quick & dirty, has gone into the teleporter with "am I the creator of the perfect system?", and this Brundlefly mutant has come out which has all the hubris of aspiring to systematised perfection, but none of the care and attention to detail of being well crafted, or good.
Sorry, the point I was trying to make is that it is extremely difficult, if at all possible, to make a WYSIWYG editor for a UI that can look vastly different depending on screen size, resolution, DPI, input device, and so on, and whose visual expression is dependent on rulesets rather than something that can be directly manipulated in a GUI.
@Plume I take your point, but at the same time, there have been visual GUI editors for CSS, which is basically doing the same thing, for decades (granted, those seem to have gone away as a result of programmers killing web design, as well).
Where I think the broader cultural impact is for software, is that you can now seemingly make a UI with no graphical UI art skills at all, and so people who don't know enough to know they shouldn't, do.
No need to design an icon for that function, just whack in something from SF Symbols.
> at the same time, there have been visual GUI editors for CSS, which is basically doing the same thing, for decades (granted, those seem to have gone away as a result of programmers killing web design, as well).
There are multiple reasons that market died, but Plume gave a big one. Today’s Web isn’t “you probably open this page in a window that’s 800+ pixels wide”. It’s largely mobile, which can have all kinds of widths. You can take Bootstrap’s approach of having several stops — small, medium, etc. — that roughly correspond with typical devices. Similar to Apple’s size classes. Even then, you don’t get the same kind of flexibility as with a better layout system, such as grid and flex in CSS. Then you want dark mode theming. And maybe other variation, too. Different fonts. Right to left. HDR. Etc., etc.
Which raises the question: how do you make a WYSIWYG editor that supports this, while still being reasonably easy to use? Apple and others have concluded that you don’t. Instead, you flip it around. You write rules in code, and do one or more previewers that show you the result in various scenarios.
I do, however, think Apple has a lot of work to do still with the details.
@Hammer - I don't think the reactive paradigm was a bad choice... others did it pretty well, whether you're looking at VueJS or Flutter. I could actually get behind modern apple technologies more than I do if it was simply executed better.
Vue cleaned up and simplified A LOT of ideas from legacy angular and what react did.
Flutter has a very clear parent-child structure, Ian Hixie did a good job of designing a system of html DOM without the html DOM.
SwiftUI is... trying so hard to make Swift, which wasn't ever a very good language to begin with (someone on this very site once called it "rubberized c++") competitive with these other languages and frameworks. Swift just isn't a very good UI programming language. It's not even very good when combined with AppKit or UIKit. Some of us have been saying that from the beginning, but that should be obvious everyone by now.
I'm all for this reactive paradigm - I've used it extensively with Vue and Flutter (and begrudgingly - react) and have been able to deliver very nice results. Apple just didn't do/design it very well, and I'm almost certain it's just because Swift is a lousy language for doing interface programming. To be fair, Objective-C wouldn't be good for reactive, either, and yes the Interface Builder paradigm is old and busted as hell at this point.
Swift is lacking taste. It's always lacked taste.
(Also - the format of your comment made me actually laugh out loud. I loved reading it!)
> 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)
It was built for "Apple cross platform" first. Just try to reuse as much as possible.
> Sorry, the point I was trying to make is that it is extremely difficult, if at all possible, to make a WYSIWYG editor for a UI that can look vastly different depending on screen size, resolution, DPI, input device, and so on, and whose visual expression is dependent on rulesets rather than something that can be directly manipulated in a GUI.
If you mean WYSIWYG editor where the layout is completely static or barely changes at runtime then yes. But your design time layout isn't static.
Interface Builder worked great for a very long time. It works great today they just don't promote it. I have my issues with some of the choices they made with Autolayout but if you make your constraints it works. Much better than SwiftUI. Mac supports different resolutions, screen sizes, it has had resizable windows, forever? And the way they did it worked just fine for like 40 years or something without the need of SwiftUI. Full screen windows? It's no problem, no SwiftUI required.
I think Apple just decided to chase a programming trend. Or maybe they want to be lazy. It doesn't matter if you are using declarative framework when you start targeting screens with vastly different asset ratios there is work to be done and there is no way around it. It doesn't sound like the greatest idea to reuse your watchOS UI on Mac where you have users with gigantic ultra wide monitors. Can you provide a great UX doing that? I don't think so.
You can make sane rules (like autolayout constraints, stylesheets, etc.) to get the most mileage out of your UI code but you can't make a great UI without looking at it. Devs quite often don't look which is why so many apps have broken layouts when you use them on an iPhone SE. SwiftUI is kind of like Apple saying "follow these rules and we got you" except they break your layout on OS updates. At least with CSS (which sucks IMO) you have certain guarantees.
> You can take Bootstrap’s approach of having several stops — small, medium, etc. — that roughly correspond with typical devices. Similar to Apple’s size classes.
Mac your window's width was never constrained to the screen width and all was fine. Size classes were never required either. I never liked size classes (the way Apple implemented them anyway). I think they made it so you couldn't tell if an IPad was in portrait or landscape unless you read the view's bounds.size.
Well, I was going to write a comment about how I took my complaining from here and dumped it into ChatGPT and asked it to adapt SwiftUI to a VueJS-like API, but I wrote an article instead. I simply can't unsee what I saw - ChatGPT did a beautiful job. Things could be so, so, soooooo much better.
If you're curious what it did/came up with -