SwiftUI List row expansion doesn’t animate smoothly; items below jump abruptly
14:47 26 Jan 2026

I’m trying to animate a row expansion inside a List when the user taps a note icon. I’m wrapping the state change in withAnimation, but the note appears with a poor animation and the rows below are pushed down without animation (they “jump” abruptly). How can I animate the expansion properly, including the layout shift of the rows below?

Here is a minimal working example that reproduces the behavior (copy into a new SwiftUI project and run):

import SwiftUI

@main
struct ExpansionApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

struct HistoryItem: Identifiable, Hashable {
    let id: UUID
    let title: String
    let note: String?
}

// MARK: - View

struct ContentView: View {
    // Keeps the sample aligned with the real screen behavior for note expansion.
    @State private var expandedNoteItems: Set = []

    private let items: [HistoryItem] = [
        HistoryItem(id: UUID(), title: "Client A - Morning shift", note: "Short note for entry 1."),
        HistoryItem(id: UUID(), title: "Client B - Field visit", note: "Longer note for entry 2 so the row expands more than the others."),
        HistoryItem(id: UUID(), title: "Client C - Training", note: nil),
        HistoryItem(id: UUID(), title: "Client D - Support", note: "Another note for entry 4."),
        HistoryItem(id: UUID(), title: "Client E - Wrap up", note: "Final note for entry 5.")
    ]

    var body: some View {
        NavigationStack {
            List {
                ForEach(items, id: \.id) { item in
                    VStack(alignment: .leading, spacing: 8) {
                        HStack(spacing: 12) {
                            Text(item.title)
                                .font(.headline)

                            Spacer()

                            if item.note != nil {
                                Button {
                                    toggleNote(for: item.id)
                                } label: {
                                    Image(systemName: "note.text")
                                        .imageScale(.medium)
                                }
                                .buttonStyle(.plain)
                            }
                        }

                        if let note = item.note, expandedNoteItems.contains(item.id) {
                            Text(note)
                                .font(.subheadline)
                                .foregroundStyle(.secondary)
                                .padding(10)
                                .background(Color(.secondarySystemBackground))
                                .clipShape(RoundedRectangle(cornerRadius: 8, style: .continuous))
                        }
                    }
                    .padding(.vertical, 8)
                }
            }
            .listStyle(.plain)
            .navigationTitle("History")
        }
    }

    private func toggleNote(for id: UUID) {
        withAnimation {
            if expandedNoteItems.contains(id) {
                expandedNoteItems.remove(id)
            } else {
                expandedNoteItems.insert(id)
            }
        }
    }
}

// MARK: - Preview

#Preview {
    ContentView()
}
ios swift list animation swiftui