Tab bar animates from first tab to restored selection at launch with .tabBarMinimizeBehavior(.onScrollDown)

[Submitted as FB23998635]

On iPhone, applying .tabBarMinimizeBehavior(.onScrollDown) to a SwiftUI TabView causes the native tab bar to briefly show the first declared tab before animating to the already-restored selection during app launch.

The selected tab is persisted with @AppStorage and is already restored before the TabView is presented. The sample contains no explicit animations, transactions, navigation containers, loading states, asynchronous work, or post-launch selection changes.

Removing .tabBarMinimizeBehavior(.onScrollDown) eliminates the launch animation entirely. Likewise, starting with .tabBarMinimizeBehavior(.never) and changing it to .onScrollDown after a one-second delay also eliminates the issue.

The behavior reproduces with three simple tabs and a direct @AppStorage selection binding.

ENVIRONMENT

• iOS 26 & 27

REPRO STEPS

  1. Build and run the attached sample.
  2. Select the "Two" tab.
  3. Force-quit the app.
  4. Relaunch the app.
  5. Observe the tab bar during launch.

ACTUAL

The tab indicator initially appears on "One", the first declared tab, then animates to the correctly restored "Two" selection.

EXPECTED

The restored tab should be selected and stationary from the first visible frame, with no launch animation.

SAMPLE CODE

struct ContentView: View {
    private enum AppTab: String, Hashable {
        case one
        case two
        case three
    }

    @AppStorage("selectedGenericTab") private var selectedTab: AppTab = .three

    var body: some View {
        TabView(selection: $selectedTab) {
            Tab("One", systemImage: "1.circle", value: AppTab.one) {
                ReproTabContent(title: "One", color: .orange)
            }

            Tab("Two", systemImage: "2.circle", value: AppTab.two) {
                ReproTabContent(title: "Two", color: .blue)
            }

            Tab("Three", systemImage: "3.circle", value: AppTab.three) {
                ReproTabContent(title: "Three", color: .green)
            }
        }
        .tabBarMinimizeBehavior(.onScrollDown)
    }
}

private struct ReproTabContent: View {
    let title: String
    let color: Color

    var body: some View {
        ZStack {
            color.opacity(0.2)
                .ignoresSafeArea()

            Text(title)
                .font(.largeTitle)
        }
    }
}

A native-only workaround is to start the TabView with minimization off, then switch to .onScrollDown after its initial presentation.

In my testing, this lets the restored selection settle before minimization is applied, preventing the animation from the first tab to the restored tab. The tab bar then minimizes normally after the one-second delay.

The tradeoff is that scroll-driven minimization is unavailable during that first second.

Many of Apple’s first-party iPhone apps restore the previously selected tab at launch while also supporting tab bar minimization, so this shouldn’t require an app-level workaround.

Workaround

struct ContentView: View {
    @AppStorage("selectedGenericTab")
    private var selectedTab: AppTab = .three

    @State private var minimizeBehavior: TabBarMinimizeBehavior = .never

    var body: some View {
        TabView(selection: $selectedTab) {
            // Tabs…
        }
        .tabBarMinimizeBehavior(minimizeBehavior)
        .task {
            guard minimizeBehavior == .never else { return }

            do {
                try await Task.sleep(for: .seconds(1))
            } catch {
                return
            }

            minimizeBehavior = .onScrollDown
        }
    }
}

Thanks for reporting and isolating.

I've shared the workaround along with your report. There should be a way you are able to add to the discussion yourself through Feedback Assistant for future reference.

This looks like a bug to me.

.tabBarMinimizeBehavior(.onScrollDown) appears to be initializing its internal state before the @AppStorage selection binding has settled, causing it to treat the subsequent restoration as a tab change and animate accordingly. Your workaround confirms it's a race condition.

Updates will be provided to you through Feedback Assistant. There, you can track if the report is still being investigated, has a potential identified fix, or has been resolved in another way.

 Travis

Tab bar animates from first tab to restored selection at launch with .tabBarMinimizeBehavior(.onScrollDown)
 
 
Q