# Lists

List recipes for the `swiftui-layout-components` skill.

## When to use List

`List` is the default for long vertical runs of similar rows. `Section`
headers break the rows into groups.

- `.listStyle(.grouped)` suits discovery or search pages with several sections.
- `.environment(\.defaultMinListRowHeight, 1)` removes the minimum row height
  for very dense layouts.
- Stable row ids keep insert and delete animations and scroll positioning
  correct.

## Feed with scroll to top

```swift
struct ActivityFeed: View {
    let events: [ActivityEvent]
    @Environment(\.jumpToTop) private var jumpToTop
    @State private var position = ScrollPosition(idType: ActivityEvent.ID.self)

    var body: some View {
        List {
            ForEach(events) { event in
                ActivityRow(event: event)
                    .id(event.id)
                    .listRowInsets(EdgeInsets(top: 10, leading: 16, bottom: 10, trailing: 16))
                    .listRowSeparator(.hidden)
            }
        }
        .listStyle(.plain)
        .scrollPosition($position)
        .onChange(of: jumpToTop) {
            withAnimation { position.scrollTo(edge: .top) }
        }
    }
}
```

`jumpToTop` stands for any signal, such as a counter the tab bar bumps when
its tab is tapped again, passed down through a custom environment value.

## Settings list

```swift
struct PrivacySettings: View {
    var body: some View {
        List {
            Section("Data") {
                NavigationLink("Location", value: PrivacyPage.location)
                NavigationLink("Contacts", value: PrivacyPage.contacts)
            }
            Section {
                Button("Delete Account", role: .destructive) { confirmDeletion() }
            }
        }
        .listStyle(.insetGrouped)
    }

    private func confirmDeletion() {}
}
```

## Swipe actions on rows

Swipe actions are a `List` row feature; the full guide with an example is in
the parent skill under [Swipe actions](../SKILL.md#swipe-actions). Short version: put
`.swipeActions(edge:allowsFullSwipe:content:)` on the row inside `ForEach`,
use `role: .destructive` for delete, `.tint(_:)` for other actions, and
mirror the actions in a context menu.

## Edge effect (iOS 26)

```swift
List(items) { ItemRow(item: $0) }
    .scrollEdgeEffectStyle(.soft, for: .top)
```

The full edge-effect API is covered in the
[scroll view reference](scrollview.md).

## Pitfalls

- Heavy custom layouts inside rows; switch to `ScrollView` with `LazyVStack`.
- A `ScrollView` nested in a `List` fights over gestures.
