iPadOS 26 - TableView auto scrolling bug

We are observing that for devices with iPadOS 26, table views within apps are unexpectedly auto scrolling. The issue can be reproduced as follows:

  1. The table view has enough cells to the point where not all cells can fit on the screen and the table view is scrollable
  2. User has scrolled to the bottom of the tableView and tableView.reloadData() is called.
  3. One of the following applies:
  • The ViewController containing the tableView is embedded in a UINavigationController, and ViewController sets self.edgesForExtendedLayout = .bottom
  • The ViewController containing the tableView is embedded in a UINavigationController, and UINavigationController sets navigationBar.isTranslucent = false
  • The following constraints are applied to the tableView:
tableView.topAnchor.constraint(equalTo: view.layoutMarginsGuide.topAnchor).isActive = true
tableView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
tableView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true

After thorough testing, we've found that the bug is only present in iPads with iPadOS 26. It does not show for iPhone devices or for iPads on iPadOS 18. We are hoping that this can be fixed as it is causing poor user experience.

Full code needed to reproduce the issue:

Use this willConnectTo function in SceneDelegate:

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        guard let windowScene = scene as? UIWindowScene else { return }
        window = UIWindow(windowScene: windowScene)
        
        let navigationControllerWithVC = UINavigationController(rootViewController: ViewController())
        // ⚠️ CASE 1 - Comment out the .isTranslucent setter below, or set the value to true, and the scrolling issue will be gone, granted that the other issue-causing lines in ViewController.swift
        // are also commented.
        navigationControllerWithVC.navigationBar.isTranslucent = false
        window?.rootViewController = navigationControllerWithVC // Replace this line with window?.rootViewController = ViewController() to get rid of UINavigationController
        window?.makeKeyAndVisible()
    }

Use this ViewController class that is referenced from the SceneDelegate willConnectTo function:

import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    
    var tableView: UITableView!
    var safeArea: UILayoutGuide!
    var timer: Timer!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // ⚠️ CASE 2 - Uncomment the line below when this view is inside a UINavigationController to cause the scrolling issue.
        //self.edgesForExtendedLayout = .bottom
        
        tableView = UITableView()
        safeArea = view.layoutMarginsGuide
        setupTableView()
        timer = Timer.scheduledTimer(timeInterval: 3.0, target: self, selector: #selector(fireTimer), userInfo: nil, repeats: true)
    }
    
    @objc public func fireTimer() {
        tableView.reloadData()
        print("Reloaded table")
    }
    
    func setupTableView() {
        tableView.delegate = self
        tableView.dataSource = self
        view.addSubview(tableView)
        
        tableView.translatesAutoresizingMaskIntoConstraints = false
        // ⚠️ CASE 3 - Replace view.topAnchor in the next line below with safeArea.topAnchor to see the scrolling issue, regardless if view is inside a UINavigationController.
        tableView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
        tableView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
        tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
        tableView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        40
    }
    
    public  func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        50.0
    }
    
    public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = UITableViewCell()
        cell.textLabel?.text =  indexPath.row == 39 ? "END" : "Row \(indexPath.row)"
        return cell
    }
    
    public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)
    }
}

For reproducing this on iPadOS 26 simulators, I can confirm that simulators under Xcode 26.0.1 (17A400) and Xcode 26.1 Beta (17B5025f) will show the issue. The issue is present in iPadOS 26 and iPadOS 26.1 beta.

I've also submitted Apple Feedback for this (FB20357980) with all this code in a Xcode project.

Answered by DTS Engineer in 860412022

In your code snippet you had:

navigationControllerWithVC.navigationBar.isTranslucent = false

We don't recommend using isTranslucent for this level of customization in UINavigationBar. For iOS 18 and below, use UINavigationBarAppearance for customization purposes and starting in iOS 26, reduce your use of custom backgrounds in navigation elements and controls. Prefer to remove custom effects and let the system determine the navigation bar background appearance. Please review Customizing your app’s navigation bar and TN3106: Customizing the appearance of UINavigationBar

You also called:

tableView.reloadData()

We also don't recommend you calling reloadData. Ideally use a combination of UITableViewDiffableDataSource which handles automatically diffing sections & items for you, and generating the correct batch updates on the tableView or your own change detection for properties within existing items so you can call the reconfigure or reload APIs on the diffable snapshot as needed, to update content within existing views.

Is there any chance I could get some acknowledgement from an Apple Engineer that this is being looked into?

Feedback Assistant now says there are 10 similar reports. I'm hoping this can be open-and-shut given that this is easy to reproduce with the code provided above and the circumstances. Our app is starting to get negative feedback because of this.

In your code snippet you had:

navigationControllerWithVC.navigationBar.isTranslucent = false

We don't recommend using isTranslucent for this level of customization in UINavigationBar. For iOS 18 and below, use UINavigationBarAppearance for customization purposes and starting in iOS 26, reduce your use of custom backgrounds in navigation elements and controls. Prefer to remove custom effects and let the system determine the navigation bar background appearance. Please review Customizing your app’s navigation bar and TN3106: Customizing the appearance of UINavigationBar

You also called:

tableView.reloadData()

We also don't recommend you calling reloadData. Ideally use a combination of UITableViewDiffableDataSource which handles automatically diffing sections & items for you, and generating the correct batch updates on the tableView or your own change detection for properties within existing items so you can call the reconfigure or reload APIs on the diffable snapshot as needed, to update content within existing views.

Although the code may not be using the best or latest practices, that is not the main concern.

It seems that most methods that modify the layout of the tableView, either directly or indirectly, results in the strange auto scrolling behavior. Or maybe the issue is triggered when the tableView does not fill the entire view. The mechanics of the bug are not fully known.

The conditions behind this do not seem to make sense. navigationControllerWithVC.navigationBar.isTranslucent = false for example, may not be using best practices, but why does that cause the table to start auto scrolling when being reloaded? The same can be asked for the safeArea top anchor scenario in the original code.

Disregarding all of the navigation bar stuff, consider another case where we may want to present a label or some other content above the tableView. If the setupTableView() function is replaced with the code below, this will also trigger the auto scrolling issue:

func setupTableViewWithLabelAbove() {
    tableView.delegate = self
    tableView.dataSource = self
    tableView..translatesAutoresizingMaskIntoConstraints = false

    let label = UILabel()
    label.text = "Label"
    label.textColor = .white
    label.textAlignment = .center
    label.translatesAutoresizingMaskIntoConstraints = false

    view.addSubview(label)
    view.addSubview(tableView)

    NSLayoutConstraint.activate([
            label.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 8),
            label.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16),
            label.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16),
            
            tableView.topAnchor.constraint(equalTo: label.bottomAnchor, constant: 8),
            tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
        ])
}

I strongly suspect that this is a bug given the conditions needed to trigger this, in addition to this being reproducible on iPadOS 26 only.

Similar to other threads on this forum, can I please get confirmation that this is indeed a bug and the issue has been routed to the appropriate engineering team?

iPadOS 26 - TableView auto scrolling bug
 
 
Q