Highlight
A full breakdown of how to adopt the iOS 26 new design at the UIKit layer, covering six areas: Tab, navigation bar, Presentation, search, controls, and custom Glass.
Core content
Recompile an old app against the iOS 26 SDK and the Tab Bar floats, the navigation bar turns translucent, and buttons grow a Liquid Glass background. The question is what to do next. The old UIBarAppearance, backgroundColor, and custom button tints you added “for a unified look” now cover up the glass effect. Sanaa, an engineer on the UIKit team, spends nearly 25 minutes walking through the details you have to rethink across six areas.
The thread of the whole video is this: UIKit has redone the materials and layout of Tab Bar, Split View, Navigation Bar, Toolbar, Presentation, Search Bar, Slider, Switch, and so on. The developer’s job is to delete the old customization code, then use the new APIs to configure the few details the automatic behavior cannot handle. For example, scroll-to-minimize on the Tab Bar takes one line of tabBarMinimizeBehavior; extending artwork beneath a sidebar uses UIBackgroundExtensionView; the morph transition for sheets uses preferredTransition = .zoom; custom glass goes through UIGlassEffect plus UIVisualEffectView. Each API maps to a concrete scenario, no vague talk about “flexibility.”
Details
Tab Bar and bottom Accessory (from 02:31)
// Minimize tab bar on scroll
tabBarController.tabBarMinimizeBehavior = .onScrollDown
// Add a bottom accessory
let nowPlayingView = NowPlayingView()
let accessory = UITabAccessory(contentView: nowPlayingView)
tabBarController.bottomAccessory = accessory
Key points:
tabBarMinimizeBehavior = .onScrollDown: scroll down to hide the Tab Bar, scroll up to bring it back, leaving the focus on content.UITabAccessory: hangs an auxiliary view above the Tab Bar, such as the Mini Player in a music app.- When the Tab Bar minimizes,
bottomAccessoryanimates inline into the Tab Bar and takes less space.
Adaptive accessory views (03:35):
// Update the accessory with the trait
registerForTraitChanges([UITraitTabAccessoryEnvironment.self]) { (view: MiniPlayerView, _) in
let isInline = view.traitCollection.tabAccessoryEnvironment == .inline
view.updatePlayerAppearance(inline: isInline)
}
// Automatic trait tracking with updateProperties()
override func updateProperties() {
super.updateProperties()
let isInline = traitCollection.tabAccessoryEnvironment == .inline
updatePlayerAppearance(inline: isInline)
}
Key points:
- Watch the
UITraitTabAccessoryEnvironmenttrait for the inline vs. standalone state. - Inline mode is tight on space, so hide secondary controls (the music app hides some playback controls).
updateProperties()is the automatic trait-tracking entry point introduced at WWDC25; see “What’s new in UIKit.”
Artwork extension beneath the sidebar (05:51)
// Extend content underneath the sidebar
let posterImageView = UIImageView(image: ...)
let extensionView = UIBackgroundExtensionView()
extensionView.contentView = posterImageView
view.addSubview(extensionView)
let detailsView = ShowDetailsView()
view.addSubview(detailsView)
Key points:
UIBackgroundExtensionViewfills its content view (the poster) into the area outside the safe area.- It extends along the safe area by default: the top stays clear for the status bar / navigation bar, the leading edge for the Sidebar.
- Anything you do not want extended (the show title, the episode list) goes in as a sibling, not inside
extensionView.
Navigation bar grouping and subtitles (08:38 / 10:15)
// Custom grouping
navigationItem.rightBarButtonItems = [
doneButton,
flagButton, folderButton, infoButton,
.fixedSpace(0),
shareButton, selectButton
]
// Titles and subtitles
navigationItem.title = "Inbox"
navigationItem.subtitle = "49 Unread"
Key points:
- The system groups buttons by rule: icon buttons share a glass background; text buttons, Done/Close, and prominent style get their own background.
.fixedSpace(0)forces same-kind buttons into two groups — the example splits Share off from the rest.navigationItem.subtitleis a new API in iOS 26, rendered below the title;largeSubtitleViewputs an interactive view below the large title (like Mail’s filter button).- The large title now scrolls with content, so the scroll view has to extend all the way under the navigation bar.
Edge Effect for custom containers (11:20)
// Edge effect's custom container
let interaction = UIScrollEdgeElementContainerInteraction()
interaction.scrollView = contentScrollView
interaction.edge = .bottom
buttonsContainerView.addInteraction(interaction)
Key points:
- A scroll view under a navigation bar / toolbar gets a visual treatment automatically (Scroll Edge Effect).
- A custom container floating at the edge (a floating button cluster, for example) needs
UIScrollEdgeElementContainerInteractionto wire the edge effect behind it; otherwise the text under the container smears.
Zoom Transition and Action Sheet anchors (13:55)
// Morph popover from its source button
viewController.popoverPresentationController?.sourceItem = barButtonItem
// Morph sheet from bar button
viewController.preferredTransition = .zoom { _ in
folderBarButtonItem
}
// Setting source item for action sheets
alertController.popoverPresentationController?.sourceItem = barButtonItem
Key points:
sourceItempoints at the source button, and the popover morphs out of the button’s position.preferredTransition = .zoom { ... }is for sheet-style pages: the button shape melts into the new page.- Action Sheets on iPhone now anchor to the source item too, matching iPad behavior; with no source they show centered and add a Cancel button automatically.
Search bar placement (15:36 / 17:03)
// Place search bar in a toolbar
toolbarItems = [
navigationItem.searchBarPlacementBarButtonItem,
.flexibleSpace(),
addButton
]
// Place search at the trailing edge of the navigation bar (iPad)
navigationItem.searchBarPlacementAllowsExternalIntegration = true
// Search as a dedicated view
navigationItem.preferredSearchBarPlacement = .integratedCentered
// Tab Bar search shortcut
searchTab.automaticallyActivatesSearch = true
Key points:
- On iPhone, move the search bar into the toolbar with
searchBarPlacementBarButtonItem. - On iPad, set
searchBarPlacementAllowsExternalIntegrationand the system places the search bar at the trailing edge of the navigation bar (macOS style). - A Search Tab on the Tab Bar with
automaticallyActivatesSearch = trueexpands directly into a text field on tap.
Controls: Glass Button, Slider, Switch (17:52)
// Standard glass
button.configuration = .glass()
// Prominent glass
tintedButton.configuration = .prominentGlass()
// Neutral slider with 5 ticks and a neutral value
slider.trackConfiguration = .init(allowsTickValuesOnly: true,
neutralValue: 0.2,
numberOfTicks: 5)
// Thumbless slider
slider.sliderStyle = .thumbless
Key points:
.glass()and.prominentGlass()are two new factory methods onUIButton.Configuration.- Slider gains a tick mode (
allowsTickValuesOnly), a neutral anchor (neutralValue, e.g. the zero point of a brightness slider in Photos), and a.thumblessstyle. - The thumb on Switch and Segmented Control gets the Liquid Glass interaction animation.
Custom Glass: UIGlassEffect and containers (20:28 / 23:52)
// Adopting glass for custom views
let effectView = UIVisualEffectView()
addSubview(effectView)
let glassEffect = UIGlassEffect()
glassEffect.tintColor = .systemBlue
glassEffect.isInteractive = true
UIView.animate {
effectView.effect = glassEffect
}
// Adding glass elements to a container
let container = UIGlassContainerEffect()
let containerView = UIVisualEffectView(effect: container)
let view1 = UIVisualEffectView(effect: UIGlassEffect())
let view2 = UIVisualEffectView(effect: UIGlassEffect())
containerView.contentView.addSubview(view1)
containerView.contentView.addSubview(view2)
Key points:
- Apply
UIGlassEffectto aUIVisualEffectView. Wrap the assignment inUIView.animateto trigger the materialize animation; setting it tonildematerializes. tintColortints the glass;isInteractive = trueturns on the elastic feedback on press.UIGlassContainerEffectputs several glass views in one container — they fuse when close, separate when apart;spacingsets the fuse-distance threshold.cornerConfiguration = .containerRelative()makes a child view’s corner radius track the container’s inset automatically.
Key takeaways
1. Treat “automatic migration” as the first step of redoing the UI
Why it pays off: recompiling against the iOS 26 SDK gives you most Liquid Glass effects for free. Look at the automatic result first, then decide which spots need hand-tuning. Beats rewriting from scratch by a wide margin.
How to start: build the existing app with the new SDK, screenshot every screen for comparison, and split the diffs into “automatically better” and “automatically worse.” Take the wins as is; work only on the regressions.
2. Delete the old custom Bar appearance
Why it pays off: old code like UIBarAppearance, backgroundColor, and button tints fights the Glass material directly. You will not get the new design without removing it.
How to start: grep the project for UIBarAppearance / setBackgroundImage / barTintColor and remove what you can. Keep only the tintColor plus style = .prominent that the information itself needs.
3. Redo the sidebar content with UIBackgroundExtensionView
Why it pays off: on iOS 26, a sidebar looks best when content extends underneath it (see the TV app). One or two lines of UIBackgroundExtensionView get you there.
How to start: find the detail screens that contain a sidebar, wrap the background image (poster, cover, map) inside UIBackgroundExtensionView.contentView, and add show titles / lists as siblings. Turn off automaticallyPlacesContentView for custom layouts when you need to.
4. Add ScrollEdgeElementContainerInteraction to every custom floating container
Why it pays off: the automatic edge blur applies only to system bars. A custom floating button cluster that is not wired up will smear text and buttons together below it.
How to start: list every floating button cluster and quick-action bar; add UIScrollEdgeElementContainerInteraction to their container view and set the matching scrollView and edge.
5. Wrap custom controls with UIGlassEffect where it fits
Why it pays off: in-house playback controls, track pickers, and badges still drawn on solid color look detached from the system visuals. UIGlassEffect plus UIGlassContainerEffect pull them into the Liquid Glass system.
How to start: pick the most prominent custom floating panel as a pilot, wrap it in UIVisualEffectView, set tintColor and isInteractive, and put multiple elements inside UIGlassContainerEffect to verify the fuse animation.
Related Sessions
- Build a SwiftUI app with the new design — the mirror implementation on the SwiftUI side, covering the same Tab, navigation, Presentation, and controls work.
- Make your UIKit app more flexible — the adaptive capabilities of UITab/UITabGroup; read alongside the Tab Bar section here.
- What’s new in UIKit — explains the
updateProperties()automatic trait-tracking mechanism this session keeps referencing. - Get to know the new design system — the design-language overview for Liquid Glass; the upstream design guide for these UIKit details.
Comments
GitHub Issues · utterances