A Summary of the WWDC25 Group Lab - SwiftUI

This thread has been locked by a moderator; it no longer accepts new replies.

At WWDC25 we launched a new type of Lab event for the developer community - Group Labs. A Group Lab is a panel Q&A designed for a large audience of developers. Group Labs are a unique opportunity for the community to submit questions directly to a panel of Apple engineers and designers. Here are the highlights from the WWDC25 Group Lab for SwiftUI.

What's your favorite new feature introduced to SwiftUI this year?

  1. The new rich text editor, a collaborative effort across multiple Apple teams.
  2. The safe area bar, simplifying the management of scroll view insets, safe areas, and overlays.
  3. NavigationLink indicator visibility control, a highly requested feature now available and back-deployed.
  4. Performance improvements to existing components (lists, scroll views, etc.) that come "for free" without requiring API adoption.

Regarding performance profiling, it's recommended to use the new SwiftUI Instruments tool when you have a good understanding of your code and notice a performance drop after a specific change. This helps build a mental map between your code and the profiler's output. The "cause-and-effect graph" in the tool is particularly useful for identifying what's triggering expensive view updates, even if the issue isn't immediately apparent in your own code.

My app is primarily UIKit-based, but I'm interested in adopting some newer SwiftUI-only scene types like MenuBarExtra or using SwiftUI-exclusive features. Is there a better way to bridge these worlds now?

Yes, "scene bridging" makes it possible to use SwiftUI scenes from UIKit or AppKit lifecycle apps. This allows you to display purely SwiftUI scenes from your existing UIKit/AppKit code. Furthermore, you can use SwiftUI scene-specific modifiers to affect those scenes. Scene bridging is a great way to introduce SwiftUI into your apps. This also allows UIKit apps brought to Vision OS to integrate volumes and immersive spaces. It's also a great way to customize your experience with Assistive Access API.

Can you please share any bad practices we should avoid when integrating Liquid Glass in our SwiftUI Apps?

Avoid these common mistakes when integrating liquid glass:

Overlapping Glass: Don't overlap liquid glass elements, as this can create visual artifacts.

Scrolling Content Collisions: Be cautious when using liquid glass within scrolling content to prevent collisions with toolbar and navigation bar glass.

Unnecessary Tinting: Resist the urge to tint the glass for branding or other purposes. Liquid glass should primarily be used to draw attention and convey meaning.

Improper Grouping: Use the GlassEffectContainer to group related glass elements. This helps the system optimize rendering by limiting the search area for glass interactions.

Navigation Bar Tinting: Avoid tinting navigation bars for branding, as this conflicts with the liquid glass effect. Instead, move branding colors into the content of the scroll view. This allows the color to be visible behind the glass at the top of the view, but it moves out of the way as the user scrolls, allowing the controls to revert to their standard monochrome style for better readability.

Thanks for improving the performance of SwiftUI List this year. How about LazyVStack in ScrollView? Does it now also reuse the views inside the stack? Are there any best practices for improving the performance when using LazyVStack with large number of items?

SwiftUI has improved scroll performance, including idle prefetching. When using LazyVStack with a large number of items, ensure your ForEach returns a static number of views. If you're returning multiple views within the ForEach, wrap them in a VStack to ****** to SwiftUI that it's a single row, allowing for optimizations. Reuse is handled as an implementation detail within SwiftUI. Use the performance instrument to identify expensive views and determine how to optimize your app. If you encounter performance issues or hitches in scrolling, use the new SwiftUI Instruments tool to diagnose the problem.

Implementing the new iOS 26 tab bar seems to have very low contrast when darker content is underneath, is there anything we should be doing to increase the contrast for tab bars?

The new design is still in beta. If you're experiencing low contrast issues, especially with darker content underneath, please file feedback. It's generally not recommended to modify standard system components. As all apps on the platform are adopting liquid glass, feedback is crucial for tuning the experience based on a wider range of apps. Early feedback, especially regarding contrast and accessibility, is valuable for improving the system for all users.

If I’m starting a new multi-platform app (iOS/iPadOS/macOS) that will heavily depend on UIKit/AppKit for the core structure and components (split, collection, table, and outline views), should I still use SwiftUI to manage the app lifecycle? Why?

Even if your new multi-platform app heavily relies on UIKit/AppKit for core structure and components, it's generally recommended to still use SwiftUI to manage the app lifecycle. This sets you up for easier integration of SwiftUI components in the future and allows you to quickly adopt new SwiftUI features. Interoperability between SwiftUI and UIKit/AppKit is a core principle, with APIs to facilitate going back and forth between the two frameworks. Scene bridging allows you to bring existing SwiftUI scenes into apps that use a UIKit lifecycle, or vice versa. Think of it not as a binary choice, but as a mix of whatever you need.

I’d love to know more about the matchedTransitionSource API you’ve added - is it a native way to have elements morph from a VStack to a sheet for example? What is the use case for it?

The matchedTransitionSource API helps connect different views during transitions, such as when presenting popovers or other presentations from toolbar items. It's a way to link the user interaction to the presented content. For example, it can be used to visually connect an element in a VStack to a sheet. It can also be used to create a zoom effect where an element appears to enlarge, and these transitions are fully interactive, allowing users to swipe. It creates a nice, polished experience for the user. Support for this API has been added to toolbar items this year, and it was already available for standard views.

Boost

(Continued)

Instance singleton vs EnvironmentObject for ViewModels?

While instance singletons (public static let shared) are common, especially from UIKit/AppKit development, @EnvironmentObject is preferred in SwiftUI. Singletons can make your code more difficult to test. The @EnvironmentObject property wrapper solves the problem of accessing a shared object by offering a convenient mechanism for sharing model data across your app, guaranteeing that views remain synchronized with the latest data. While singletons aren't actively harmful, they can make refactoring more difficult. @EnvironmentObject also allows you to inject different contexts to see different previews, too.

What’s the best way in SwiftUI for a View to communicate values back to its parent that cannot be overridden by the parent? Binding is not really suitable because it enables the parent to modify the values.

If you need a child View to communicate values back to its parent without allowing the parent to modify them, Binding is not suitable. Consider these approaches:

Container Values: If the parent is a container, explore container values. These values can be read by the container.

Preferences: If you need to communicate values upwards, consider using preferences. Preferences flow up the view hierarchy and you can combine multiple preferences.

Closures: Use closures, especially for performing actions or when interacting with UIKit/AppKit views.

For an example see the code in the Cook up a rich text experience in SwiftUI with AttributedString session, which demonstrates using a preference to pass the current selection up the view hierarchy.

I saw that animations are available in Widgets for visionOS. Will it also be available for widgets on iOS?

The same animation capabilities available for widgets on visionOS have been supported on iOS since iOS 17. For more information on animated and interactive widgets, refer to the Bring Widgets to Life session from WWDC 23.

Is it possible to add hyperlinks in the new rich text editor?

Yes, it is possible to add hyperlinks in the new rich text editor. Use the Foundation's link attribute. Please be aware that in seed one there's a known issue where gestures aren't behaving correctly with links.

Whats the best way to implement custom tab bars in SwiftUI?

Before implementing a fully custom tab bar, consider whether you can achieve your desired result using the standard system controls. There are APIs to customize aspects like color, labels, and even add a separate search tab. Using system controls ensures a consistent appearance across different operating systems. If a more custom design is necessary, explore the new glass APIs like GlassEffectContainer, GlassEffect, and SafeAreaBar. Please submit feedback if a missing feature prevents you from using the standard tab bar.

Is there an API to show the navigation link chevron when there isn’t a navigation link but a button?

There isn't a direct API, no. However, you can achieve a similar effect by:

  • Using an environment key for indicatorVisibility.
  • Using the trailing chevron SF Symbol, which is what navigation links are styled as.
  • Replicating the NavigationLink selection state.

Can you create custom components like the tab bar with a draggable glass droplet?

You can build custom liquid glass components using the new GlassEffect API. However, there isn't currently a specific API to replicate the "lift up" effect seen when changing selections in the system tab bar. If you have use cases requiring additional APIs for creating such effects in your custom controls, please file feedback. Providing detailed feedback with screenshots and descriptions of your use case is valuable for informing the design of future API, helping the team create simple, flexible, and composable solutions.

What’s the recommended way to display thousands of thumbnails in a LazyVGrid without dropping frames or showing empty cells while the thumbnail loads?

To display thousands of thumbnails in a LazyVGrid without dropping frames or showing empty cells:

Concurrency: Move work off the main thread. The Embracing Swift Concurrency session from WWDC25 provides guidance. The SwiftUI performance instrument can help identify issues caused by main thread work. Also see the Code-along: Elevate an App with Swift Concurrency session.

Image Scaling: Downscale high-resolution images to the actual display size.

Performance Instrument: Use this new instrument to identify expensive view initializers or bodies.

Invalidation Debugging: Use this debugging trick - set a random background color on the photo insets to visualize cell invalidation during scrolling. A "disco ball" effect indicates excessive invalidation.

Is there any way to make DatePicker respect Dynamic Type? It really seems to like rendering itself at a small size no matter what I do.

This is a known issue and unfortunately there is not a way to customize it.

A Summary of the WWDC25 Group Lab - SwiftUI
 
 
Q