I raised Popular Rank's deployment target to iOS 26, opened the build on an iPad, and the top of the screen was wrong in a way I could not immediately explain. The plus button I place in the navigation toolbar was sitting on top of the system clock and battery glyphs. My layout code had not changed at all. The platform default underneath it had, and that is a genuinely tricky class of bug to chase, because your own diff is empty while the screen is clearly broken.
The structure I started with
Popular Rank is built around a small root TabView with two tabs: Discover, where you find and generate topics to rank, and Rankings, where you review the lists you have made. Each tab wraps its content in its own NavigationStack, and that stack is where the toolbar lives. On the Rankings tab the most visible toolbar control is a create button, declared the ordinary SwiftUI way:
.toolbar {
ToolbarItem(placement: .primaryAction) {
Button {
handleCreateTap()
} label: {
Image(systemName: "plus")
.font(.body.weight(.semibold))
}
}
}
.primaryAction resolves to the trailing edge of the navigation bar, the top-right corner where iOS conventionally puts the affirmative action. On iPhone this had behaved exactly as I expected across every release I had shipped. The button sat in the navigation bar, below the status bar, clear of the system glyphs. I had no reason to think about it again.
What actually changed
iOS 26 introduced a floating tab presentation. Instead of the familiar bar anchored to a fixed edge, the system can render the tabs as a floating capsule near the top of the window on iPad. It is a real visual refresh, and on a fresh app it looks intentional and modern. The problem is that it is the new default for a standard TabView, and it reclaims vertical space at the very top of the window.
That reclaimed space is the part that bit me. When the floating tab bar moved into the top region, it shifted the geometry my per-tab navigation bars were laid out against. The trailing toolbar item, my plus button, ended up riding up into the strip the status bar owns, overlapping the clock on the left edge of my button and crowding the battery and signal indicators. Nothing was functionally broken. Taps still registered on the button. But it read as unfinished, and on iPad I really wanted the chrome to feel settled rather than improvised.
The detail worth sitting with is that I never opted into any of this. I did not touch MainTabView. I did not change a placement, a safe-area inset, or a toolbar declaration. The meaning of my existing code changed because the framework's interpretation of a plain TabView changed when the deployment target crossed into iOS 26. That is a different failure mode than a typo, and it rewards a different debugging instinct.
An assumption about a platform default can be as much a bug as a wrong line of code. The line did not change. What the line meant did.
The fix, and why it works
SwiftUI lets you state which tab presentation you want rather than accepting whatever the current OS defaults to. The modifier .tabViewStyle(.tabBarOnly) tells the framework to render the conventional tab bar and to skip the floating top presentation entirely. With the floating bar gone, the top region reverts to what my navigation bars were always laid out against, and the plus button falls back into its proper place below the status bar.
TabView(selection: Bindable(coordinator).selectedTab) {
DiscoverTab()
.tabItem { Label("Discover", systemImage: "magnifyingglass") }
.tag(NavigationCoordinator.Tab.discover)
MyRankingsTab()
.tabItem { Label("Rankings", systemImage: "star.fill") }
.tag(NavigationCoordinator.Tab.myRankings)
}
.tabViewStyle(.tabBarOnly)
That is the entire change: a single modifier on the root TabView. The commit that shipped it touched one file and added one line. There is a small irony in writing several hundred words about a one-line diff, but the line is the cheap part. Knowing which line, and why, was the expensive part, and that is the reusable knowledge.
I want to be honest about the tradeoff, because opting out of a new platform default is a decision, not a free win. The floating tab bar is where Apple is heading on iPad, and choosing .tabBarOnly means I am holding the older presentation for now. I made that call deliberately: my toolbar layout and the floating bar were fighting over the same vertical space, and the conservative presentation was the one that kept the app feeling coherent across iPhone and iPad in this release. When I am ready to redesign the top chrome around the floating bar properly, I will revisit it. Opting out today is a considered pause, not a refusal.
Why it stayed hidden for so long
The real lesson here is about test coverage across device classes, not about any one SwiftUI modifier. I exercise the iPhone build constantly, because that is where almost all of the usage lives, so any iPhone regression surfaces within minutes. iPad gets attention far less often. The floating tab change happened to land on iPad only, which means it appeared on exactly the device I run least. That is not a coincidence so much as a pattern: this category of platform-default regression tends to hide on the surface you neglect.
It also misdirected me at first. When a screen is wrong but your source is unchanged, the natural reflex is to suspect your own layout: a safe-area handling mistake, a stray toolbar placement, an inset that drifted. I spent time looking there before I stepped back and asked a more useful question. Not "what did I do wrong," but "what changed in the platform between the last release I tested on and this one?" Framed that way, the answer pointed straight at the new tab presentation, and from there the opt-out modifier was a short search through the documentation.
- Build and open the app on every device class you ship to, not just the one you reach for daily. The neglected surface is where shifted defaults like to live.
- When a layout breaks and your diff is empty, suspect a moved platform default before you suspect your own code. The instinct to re-read your layout is strong and often misleading.
- Read the release notes for the OS version you raise your deployment target to. Default rendering can change without a single API breaking or deprecating, so nothing warns you at compile time.
- State the presentation you want explicitly when it matters.
.tabViewStyle(.tabBarOnly)turns an implicit default into an intentional, documented choice you can revisit on your own schedule.
Takeaway
The code change was a single modifier on the root TabView. The actual work was recognizing that a default had quietly moved, that the device I tested least was where it would surface, and that opting out was a deliberate decision with a tradeoff rather than a magic fix. I am keeping two things from this one. A clean diff does not mean a clean screen. And when the framework changes its mind about what your code means, the most direct path back is to stop reading your own source and start reading the platform's release notes.