Skip to content

FB23687733: SwiftUI List: Moving an item between List sections via swipeActions breaks row animations in iOS 26.5 and iOS 27b3 (Regression from iOS 18.6) #820

Description

@malhal

Submission Date

2026-07-11

Status

Open

Area

SwiftUI

Operating System Version

iOS 27b3

Type

Incorrect/Unexpected Behavior

Description

There is a visual regression in List row animations when an item transitions between two Section blocks via a swipeActions trigger.

In iOS 18.6, toggling a property that determines an item's section membership results in a smooth, continuous transition (the row elegantly slides out of one section and slides into the target section). In iOS 26 and iOS 27b3, the row abruptly vanishes from its source section, glitches the surrounding list layout height, and instantly snaps into the destination section without fluid tracking.

Steps to Reproduce:
Run the attached minimal reproducible sample on an iOS 26.5 or iOS 27b3 device/simulator.
Swipe left on a row in the secondary section and trigger the "Favorite" swipe action.
Observe the broken, abrupt layout pop instead of a clean cross-sectional transition.

Expected Behavior:
The row should utilize the standard spatial layout transitions, tracking seamlessly between sections exactly as it does in iOS 18.6.
Configuration Context:
Regression Observed In: iOS 26.5, iOS 27b3
Working Baseline: iOS 18.6
Related Feedback Reference: FB23661327

Minimal Reproducible Example (Code)

import SwiftUI

struct ListSectionsSwipeActionsSingle: View {
    @Observable
    class Item: Identifiable {
        init(
            id: Int,
            isFavorite: Bool
        ) {
            self.id = id
            self.isFavorite = isFavorite
        }
        
        var id: Int
        var isFavorite: Bool
    }
    
    @State private var items: [Item] = [
        .init(id: 0, isFavorite: false),
        .init(id: 1, isFavorite: false),
        .init(id: 2, isFavorite: true),
        .init(id: 3, isFavorite: false),
        .init(id: 4, isFavorite: false),
        .init(id: 5, isFavorite: true),
        .init(id: 6, isFavorite: false),
        .init(id: 7, isFavorite: true),
        .init(id: 8, isFavorite: true),
        .init(id: 9, isFavorite: false),
        .init(id: 10, isFavorite: false),
    ]
    
    private var favorites: [Item] {
        return items.filter(\.isFavorite)
    }
    
    private var notFavorites: [Item] {
        return items.filter { return !$0.isFavorite }
    }
    
    var body: some View {
        NavigationStack {
            List {
                if !favorites.isEmpty {
                    Section("Favorites") {
                        ForEach(favorites) { item in
                            Row(item: item)
                        }
                    }
                }
                
                Section {
                    ForEach(notFavorites) { item in
                        Row(item: item)
                    }
                }
            }
        }
    }
    
    struct Row: View {
        let item: Item
        
        private func favoriteUnfavorite(item: Item) {
            withAnimation(.bouncy) {
                item.isFavorite.toggle()
            }
        }
        
        var body: some View {
            Button {
                favoriteUnfavorite(item: item)
            } label: {
                HStack {
                    Text(item.id.formatted())
                        .font(.title.weight(.semibold))
                    
                    Spacer()
                    
                    if item.isFavorite {
                        Image(systemName: "star.fill")
                    }
                }
            }
            .swipeActions {
                Button {
                    favoriteUnfavorite(item: item)
                } label: {
                    Label(
                        item.isFavorite ? "Favorite" : "Undo",
                        systemImage: "star"
                    )
                    .symbolVariant(item.isFavorite ? .slash : .none)
                }
                .tint(.green)
            }
        }
    }
    
  
}

#Preview {
    ListSectionsSwipeActionsSingle()
}

Keywords

No response

Prerequisites

  • The title follows the format FB<number>: <title>
  • I will keep this issue updated with Apple's responses

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions