Quickie: Programmatic navigation in the age of Tabs and Tab roles

A dirt road on the background is complemented by a yellow traffic sign with an arrow pointing right.
Photo by Javier Quiroga on Unsplash.

So in my previous Quickie post I mentioned I had to depart from .tag() in my app's main view because I started using Tab for the phone UI as well since I wanted to use the new role: .search option.

Well, inspired by other discoveries in my iOS 26 exploration I decided to dig a little bit more and found that programmatic navigation (meaning we navigate to a different app tab when the user takes some action) is not hard at all in the current iteration of SwiftUI iOS 26 provides us.

Let's first take a look at the problem I'm trying to solve.

0:00
/0:09

As you can see above, whenever a user taps an item in the Top Shared ranking I want to navigate to that exact sound in the main tab's grid.

This is achieved by having a tab enum at the top level that is bound to the TabView.

import SwiftUI

enum AppTab: Hashable {

    case sounds, reactions, trends
}

struct MainView: View {

    @State private var tabSelection: AppTab = .sounds

    var body: some View {
        TabView(selection: $tabSelection) {
            Tab("Sounds", systemImage: "headphones", value: .sounds) {
                VStack {
                    Image(systemName: "globe")
                        .imageScale(.large)
                        .foregroundStyle(.tint)
                    Text("Hello, world!")
                }
                .padding()
            }

            Tab("Reactions", systemImage: "rectangle.grid.2x2", value: .reactions) {
                VStack {
                    Text("Reactions")
                }
            }

            Tab("Trends", systemImage: "chart.line.uptrend.xyaxis", value: .trends) {
                VStack {
                    Text("Trends")

                    Button("Go to Sounds") {
                        // more
                    }
                }
            }
        }
    }
}

The important part here is the value: param at the end. I really wish this – along with other SwiftUI APIs – was easier to parse.

A screenshot from Xcode showing autocomplete options for the Tab SwiftUI component. There are too many options.
I mean good luck finding this signature in your first try.

This gets us here:

A screenshot of the code presented below running in Xcode's canvas. A simple tab bar with 3 tabs can be seen below and some placeholder text in the middle of the phone.

Now for the actual navigation. I'll create a subview so we can see Binding in action.

import SwiftUI

struct TrendsView: View {

    @Binding var tabSelection: AppTab

    var body: some View {
        NavigationView {
            VStack {
                Button("Go to Sounds") {
                    tabSelection = .sounds
                }
            }
            .navigationTitle("Trends")
        }
    }
}

And then we go back to MainView and replace the last tab's code with:

TabView(selection: $tabSelection) {

    // other code...

    Tab("Trends", systemImage: "chart.line.uptrend.xyaxis", value: .trends) {
         TrendsView(tabSelection: $tabSelection)
    }
}

Voilà, you got some programmatic navigation going:

0:00
/0:07

Programmatic navigation, baby.

As far as I can tell, this is the modernest way of doing Tabs in SwiftUI. This is useful for both phones and iPads and allows you to neatly integrate with the roles I described in the previous post. Have fun!

See you next time.