# The iOS 26 Search Tab in SwiftUI: Tab(role: .search) and a NavigationStack Trap

Ilyas Hallak 4 min read
Table of Contents

Readeck is a reader, and iOS 26 finally gave search a proper home in the tab bar. You can now mark one tab as the search tab, and I used that to fold search and the app’s whole menu into a single place. It is a lovely idea that also cost me weeks of grief, and I want to walk through both sides.

I built this on top of my earlier tab bar migration, so this is the iOS 26 sequel to that story. The auto-minimizing tab bar I paired it with got its own post, so this one stays about search.

One tab for search and everything elseLink to heading

The nicest idea I borrowed from Apple’s Podcasts app is that search does not need its own screen. It can be the menu. So on iOS 26 the magnifying glass tab holds both.

Tab("Search", systemImage: "magnifyingglass", value: .search, role: .search) {
NavigationStack {
VStack(spacing: 0) {
moreTabContent
moreTabsFooter
}
.searchable(text: $searchViewModel.searchQuery, prompt: "Search bookmarks...")
}
}

The trick is what sits inside. When the search field is empty, the tab shows a normal menu list. Start typing and the same surface becomes search results.

private var moreTabContent: some View {
if searchViewModel.searchQuery.isEmpty {
moreTabsList // Articles, Videos, Pictures, Tags, Settings
} else {
searchResultsView
}
}

Tab(role: .search) tells the system this is search, so it gets the native treatment instead of a hand-rolled search bar. One tab now carries the search field, the section list, and the entry point to Settings.

Here is the honest part. This collapses a lot into one place, which I like, but it also surprised people. More than one user went looking for Settings and did not think to tap the magnifying glass to find it. In Podcasts the thing behind search is the Explore area, which is semantically close to searching. Stuffing Settings back there is a slightly harder sell, and if I did it again I would think twice about what actually belongs behind a search tab.

Getting the search tab to actually workLink to heading

For weeks the search behavior was genuinely broken, and at the time I could not tell you why. Digging back through the history, the cause was structural, not a stray bug.

The old layout wrapped a single NavigationStack around the entire TabView:

// ❌ Don't: one NavigationStack around the whole TabView
NavigationStack {
TabView(selection: $selectedTab) {
Tab("Unread", systemImage: "tray", value: .unread) {
UnreadList()
}
Tab("Search", systemImage: "magnifyingglass", value: .search, role: .search) {
content
.searchable(text: $searchQuery) // no stack of its own to attach to
}
}
}

That is fine until you put .searchable on a Tab(role: .search), because .searchable needs to live inside that tab’s own navigation stack, not a shared one on the outside. With one stack wrapped around everything, the search tab had no stack of its own to attach to, and the whole thing behaved erratically.

The fix was to invert it: drop the outer stack and give each tab its own NavigationStack, with search living inside the search tab:

// ✅ Do: no outer stack, each tab owns its NavigationStack
TabView(selection: $selectedTab) {
Tab("Unread", systemImage: "tray", value: .unread) {
NavigationStack(path: $unreadPath) {
UnreadList()
}
}
Tab("Search", systemImage: "magnifyingglass", value: .search, role: .search) {
NavigationStack {
content
.searchable(text: $searchQuery) // now inside the search tab's own stack
}
}
}

It sounds obvious written down. It was not obvious at 10pm fighting a fresh .0 API, which also threw compiler errors on the new Tab() syntax and sent me reverting to the old .tabItem before getting it right. The lesson I took from it: on iOS 26, where .searchable sits in the navigation hierarchy is the whole ballgame.

The takeawayLink to heading

Tab(role: .search) is a small API with a big personality. It lets one tab carry search, the menu, and everything behind it, which is convenient for you and occasionally confusing for someone else, so choose what lives back there with care. But the thing that actually cost me weeks was not the search API at all. It was where the old NavigationStack was sitting.

My avatar

Thanks for reading my blog post! Feel free to check out my other posts or contact me via the social links in the footer.


More Posts