# List and Section ## Intent Use `List` for feed-style content and settings-style rows where built-in row reuse, selection, and accessibility matter. ## Core patterns - Prefer `List` for long, vertically scrolling content with repeated rows. - Use `Section` headers to group related rows. - Pair with `ScrollViewReader` when you need scroll-to-top or jump-to-id. - Use `.listStyle(.plain)` for modern feed layouts. - Use `.listStyle(.grouped)` for multi-section discovery/search pages where section grouping helps. - Apply `.scrollContentBackground(.hidden)` + a custom background when you need a themed surface. - Use `.listRowInsets(...)` and `.listRowSeparator(.hidden)` to tune row spacing and separators. - Use `.environment(\\.defaultMinListRowHeight, ...)` to control dense list layouts. ## Example: feed list with scroll-to-top ```swift @MainActor struct TimelineListView: View { @Environment(\.selectedTabScrollToTop) private var selectedTabScrollToTop @State private var scrollToId: String? var body: some View { ScrollViewReader { proxy in List { ForEach(items) { item in TimelineRow(item: item) .id(item.id) .listRowInsets(.init(top: 12, leading: 16, bottom: 6, trailing: 16)) .listRowSeparator(.hidden) } } .listStyle(.plain) .environment(\\.defaultMinListRowHeight, 1) .onChange(of: scrollToId) { _, newValue in if let newValue { proxy.scrollTo(newValue, anchor: .top) scrollToId = nil } } .onChange(of: selectedTabScrollToTop) { _, newValue in if newValue == 0 { withAnimation { proxy.scrollTo(ScrollToView.Constants.scrollToTop, anchor: .top) } } } } } } ``` ## Example: settings-style list ```swift @MainActor struct SettingsView: View { var body: some View { List { Section("General") { NavigationLink("Display") { DisplaySettingsView() } NavigationLink("Haptics") { HapticsSettingsView() } } Section("Account") { Button("Sign Out", role: .destructive) {} } } .listStyle(.insetGrouped) } } ``` ## Design choices to keep - Use `List` for dynamic feeds, settings, and any UI where row semantics help. - Use stable IDs for rows to keep animations and scroll positioning reliable. - Prefer `.contentShape(Rectangle())` on rows that should be tappable end-to-end. - Use `.refreshable` for pull-to-refresh feeds when the data source supports it. ## Pitfalls - Avoid heavy custom layouts inside a `List` row; use `ScrollView` + `LazyVStack` instead. - Be careful mixing `List` and nested `ScrollView`; it can cause gesture conflicts.