Skip to content
intermediate Phase 2 · SwiftUI Fundamentals

Lists & Navigation

Build scrollable lists with List, ForEach, swipe actions, search, and NavigationStack.

50m
3 problems
Topic Progress 0%

List & ForEach

Basic List

List is a container that displays rows of data in a scrollable, platform-styled layout. It provides built-in separation, insets, and swipe behavior.

struct FruitList: View {
    let fruits = ["Apple", "Banana", "Cherry", "Date", "Elderberry"]
    
    var body: some View {
        List(fruits, id: \.self) { fruit in
            Text(fruit)
        }
    }
}

List with Identifiable Data

For custom types, conform to Identifiable or provide an id key path:

struct Fruit: Identifiable {
    let id = UUID()
    let name: String
    let color: Color
}

struct FruitList: View {
    let fruits = [
        Fruit(name: "Apple", color: .red),
        Fruit(name: "Banana", color: .yellow),
        Fruit(name: "Cherry", color: .red)
    ]
    
    var body: some View {
        List(fruits) { fruit in
            HStack {
                Circle()
                    .fill(fruit.color)
                    .frame(width: 20, height: 20)
                Text(fruit.name)
            }
        }
    }
}

ForEach for Repeated Views

ForEach generates views from a collection. It works inside List, VStack, or any container:

VStack {
    ForEach(0..<5) { index in
        Text("Row \(index)")
    }
}

// With identifiable data
ForEach(fruits) { fruit in
    Text(fruit.name)
}

ForEach is not a view itself -- it generates content within a parent container. It requires stable identifiers to correctly track items across updates.

List with Sections

Organize content into sections with headers and footers:

List {
    Section("Fruits") {
        ForEach(fruits) { fruit in
            Text(fruit.name)
        }
    }
    Section("Vegetables") {
        ForEach(vegetables) { veg in
            Text(veg.name)
        }
    }
}
.listStyle(.insetGrouped)

List Styles

List { /* content */ }
    .listStyle(.plain)           // minimal separators
    .listStyle(.insetGrouped)   // grouped with insets (default on iOS)
    .listStyle(.inset)          // inset without grouping
    .listStyle(.grouped)        // full-width grouped
    .listStyle(.sidebar)        // for sidebar navigation

Dynamic deletion

struct EditableList: View {
    @State private var items = ["Item 1", "Item 2", "Item 3"]
    
    var body: some View {
        List {
            ForEach(items, id: \.self) { item in
                Text(item)
            }
            .onDelete(perform: deleteItems)
        }
        .toolbar {
            EditButton()
        }
    }
    
    func deleteItems(at offsets: IndexSet) {
        items.remove(atOffsets: offsets)
    }
}

List Row Actions

List {
    ForEach(messages) { message in
        Text(message.text)
            .swipeActions(edge: .trailing) {
                Button(role: .destructive) {
                    delete(message)
                } label: {
                    Label("Delete", systemImage: "trash")
                }
                Button {
                    archive(message)
                } label: {
                    Label("Archive", systemImage: "archivebox")
                }
                .tint(.blue)
            }
            .swipeActions(edge: .leading) {
                Button {
                    toggleRead(message)
                } label: {
                    Label(
                        message.isRead ? "Unread" : "Read",
                        systemImage: message.isRead ? "envelope.open" : "envelope"
                    )
                }
                .tint(.orange)
            }
    }
}

Quiz

1. What must data conform to for use in ForEach?

Question 1 options

2. What is the difference between .sheet() and .fullScreenCover()?

Question 2 options

3. How do you add a search bar to a list?

Question 3 options

4. What replaced NavigationView in modern SwiftUI?

Question 4 options

5. How do you add swipe actions to a list row?

Question 5 options

Flashcards

Question

What is List in SwiftUI?

Answer

A scrollable container that displays rows with built-in platform styling, separators, and swipe actions.

Question

What replaced NavigationView?

Answer

NavigationStack, which supports programmatic navigation via NavigationPath and type-safe destinations.

Question

How do you add search functionality?

Answer

Use .searchable(text:prompt:) modifier on a list or navigation container.

Question

What is NavigationPath?

Answer

A type-erased stack of navigation destinations that supports programmatic push/pop and state restoration.

Question

What is the difference between .onDelete and .swipeActions?

Answer

.onDelete provides a simple delete button. .swipeActions allows multiple custom actions with different colors and icons.

Revision Notes

Key Takeaways

  • 1. List provides built-in styling, separators, and scroll behavior
  • 2. ForEach requires stable identifiers via Identifiable or id key path
  • 3. NavigationStack replaces NavigationView with programmatic navigation support
  • 4. .searchable() adds integrated search with suggestions and keyboard handling
  • 5. .swipeActions() provides customizable trailing and leading row actions

Interview Tips

  • Explain the difference between List and ForEach (container vs generator)
  • Know when to use .sheet vs .fullScreenCover
  • Be ready to discuss programmatic navigation with NavigationPath
  • Understand how to add search, swipe actions, and pull-to-refresh to lists

Cheat Sheet

List: scrollable rows with platform styling.
ForEach: generates views from collections, requires stable IDs.
Swipe actions: .swipeActions(edge:) with .tint() for colors.
Search: .searchable(text:prompt:) for integrated search bars.
NavigationStack: modern navigation with NavigationPath.
NavigationLink: pushes views; .navigationDestination for programmatic.
Sheets: .sheet() partial, .fullScreenCover() full screen.