A SwiftUI Wish List

From its start, SwiftUI has tried to provide sensible defaults for building common UIs, but it’s taken longer to approach the full breadth of customizations offered by UIKit and AppKit. It could also afford to: the ability to bridge to and from “the kits” was (and remains) a fantastic tool for piecemeal adoption. But much like Swift’s interoperability with Objective-C, the friction of this bridging has become more noticeable over time, especially as Apple adds more SwiftUI-only frameworks (like Charts and WidgetKit). So for SwiftUI’s 6th birthday I think I could sum up most of my wishes as features that let the framework stand on its own. One of these is a big ask, while the others focus on smaller, more specific APIs.

A quick note: if you don’t know me (and this is my first post) why not check out my about page.

I had planned to publish this for WWDC25. That’s now passed, but I didn’t want to just sit on this for a year, so I guess consider this a really early list for WWDC26!

More framework fundamentals

There’s a lot of stuff I could ask for from SwiftUI, but if I just got one I’d want it to be something big, making possible (or simple) whole categories of functionality. We were fortunate enough to get some of those last year with Subview and ContainerValues and the year before with Layout. Next I’d like to see something similar for lifetime.

How SwiftUI automatically manages the lifetime of views is one of its core innovations over UIKit or AppKit. It frees you from the tedium of explicitly creating and destroying objects, avoids mental overhead of careful view reuse, and prevents whole classes of consistency bugs with its declarative, data-driven design. All you have to do is hand off a cheap view definition and the framework decides how to do the rest. It’s something you almost never need to think about… until you do. This makes proposing an API tricky, because it’s something you’d like for people to not need. For example, lifetime control is important for implementing containers such as TabView or NavigationStack[1], where views (such as inactive tabs of a TabView, or non-top views of a NavigationStack) don’t “disappear” just because they’re no longer visible. Ideally developers could conform to the respective *Style protocols for these views, but I still wish it were at least possible to implement containers like these from scratch. Instead, all that’s possible today is to approximate them.

A more complex example might be Xcode’s editor views. As you open documents, the previous editor gets replaced, but you can always go back and forward with the state of each editor preserved. This is something you could partially achieve by ensuring state is held by controller objects allocated outside of a particular view (which is often a good practice in general), but at a certain point it can become tedious and error prone. Plus, what about the private @State inside views that you don’t control? SwiftUI’s own containers avoid this issue by keeping views “alive” even when not onscreen. You could still argue that this functionality would be better served by changing NavigationStack to support bidirectional navigation (and I would agree!), but if SwiftUI can offer APIs like navigationDestination(for:destination:) I’d like to be able to as well.

There really isn’t any one use case for which SwiftUI couldn’t provide a tailored, first-class API, and that’s not my argument here either. Rather, I think that developers will always have needs that race ahead of the framework, and that it is important to give them tools to unblock themselves. SwiftUI’s automatic handling of lifetime is fantastic, but just like how Swift has now given us Span to provide both safe and performant memory access, I have faith that SwiftUI could come up with an API for safe and developer-controlled lifetime management.

More uses for Transaction

Here’s another wish that needs careful handling, but I really think that Transaction is underutilized by SwiftUI today. Transactions can be used as a general purpose tool for setting additional data while performing state updates (and that’s state in the general sense, not just @State). This is similar to how the environment lets you pass data down the view tree, allowing for loose coupling of things like animations. In fact, animations make up most of the framework-provided functionality, but you can see other interesting applications in APIs like Transaction.dismissBehavior. By customizing the current transaction, you can perform the same updates with different results.

Transaction also supports custom TransactionKeys, just like EnvironmentKey and PreferenceKey, but the applications of these are limited. While you can write to the current transaction at any time, only a handful of APIs provide you a way to read from it. The most common of these is in Binding.init(get:set:), but that comes with tradeoffs of its own.

For this reason, I’d love to see SwiftUI offer additional ways to read from the current transaction. Some ideas for how this could be useful include small things, like allowing a single Controller.doSomething() method to record different analytics based on a custom Tranaction.provanance property, or in more impactful ways (as with dismissBehavior) by providing a way for apps to override default behaviors in their own logic. I think it would be particularly useful when implementing representable types (like UIViewRepresentable), where UIKit views occasionally need to handle programatic updates differently from user-initiated ones. Setting flags as private instance properties on your UIView (a common pattern for this) maps to the behavior of withTransaction(_:_:) nicely. You might also want to call a bespoke MyUIView.setValue(_:animated:) method, setting animated: only when the current Transaction.animation is nil.

There are also reasons to be hesitant about making Transaction too enticing. It works best as a secondary tool, where data dependencies and explicit method arguments are usually the better choice. In this way I consider the transaction a bit like NotificationCenter: it can be misused and overused, but sometimes it’s also the right abstraction. To control for this, I wouldn’t mind if we could just get an overload of View.onChange(of:initial:_:) which provided a Tranasction to its action closure, or to have some way to read them from methods like UIViewRepresentable.updateUIView(_:context:).

Interactive transiting APIs

Because of SwiftUI’s decision to drop the concept of view controllers (which was a great decision, IMO) they’ve had to reinvent numerous view controller APIs as a result. We’ve gotten a good set of presentation*() modifiers to date, but a few more would be welcome. I still miss some functionality like UIViewControllerTransitionCoordinator.animate(alongsideTransition:completion:)[2], UISheetPresentationController.animateChanges(_:), or ways to detect when an interactive transition begins or ends.

Text field visual customization

Text input customization is full of nuance. There are lots of different frames to consider, some of which might influence where the cursor appears, where interaction may trigger editing, and where the insertion starts upon editing. Not to mention that each OS update keeps adding more system behaviors which need to work with existing inputs. The built in TextField styles handle this for you, but when you want to do something different it can often require dropping all the way down to UIKit.

This is a great opportunity for SwiftUI to provide something better, whether by making TextFieldStyle’s requirements public, or adding new ways to customize styles and install gestures. Some inspiration could even come from the way SwiftUI handled window customization with APIs like WindowDragGesture or containerBackground(_:for:). I could imagine a similar family of control modifiers, like a controlBackground(_:for:) and controlBorder(_:for:), which would give developers more options when using framework-provided styles.

Additional flexibility for input validation

Continuing on the theme of text editing, last year brought us support for the new Foundation ParseableFormatStyle protocol in TextField. This provides a simple way to express a complex feature, leaning in to SwiftUI’s declarative syntax, but it can still be a little hard to use. For example, numeric formatters will apply formatting that either succeeds or fails, but in either case will overwrite the text field’s value. A nicer experience might be to keep the invalid input for the user to edit further, but this requires the developer to manage an additional piece of intermediary state for pending values.

A source code editor API

Last, a wild card. I’d love to see some kind of SourceEditor API, a drop-in replacement for TextEditor, but for source code. Supporting syntax highlighting of common languages, completions, and source annotations would provide options for lots of apps. Productivity apps could offer a built-in scripting feature using JavaScript and JavaScriptCore without building their own mini IDE. Data analysis apps could use this with editing disabled to display nicely formatted JSON. I could even see this being useful in less obvious applications, like messaging clients, where a sans-serif font makes for an easy rich text Markdown editor.

While there are good third-party packages that exist for this too, I think having a high quality framework provided option unlocks a lot of uses that are otherwise out of reach today.


There’s a lot more I could say here, so if you’d like to read more in the future, why not subscribe? You can sign up for email notifications or just follow the web feed.

I’m still working on exactly where I want to take this blog, but I’ve wanted to give technical writing a shot for a while now. I’ve got some “how to” posts in mind, posts about how I approach problem solving, and just general advice. If things go well I might look into answering reader questions even.

Comments aren’t set up here yet, but you can reach me on Mastodon (bridged to Bluesky) or by email. Thanks for reading!


  1. You can get close using UIHostingController instances to hold on to isolated view graphs. However, this still won’t let you match all the behaviors or the ergonomics of SwiftUI’s own APIs. ↩︎

  2. The functionality, but not necessarily the verbosity. ↩︎

Subscribe to A Devlog

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe