Skip to content

Mastering List (SwiftUI)

A SwiftUI guide for coding agents. Also covers list sections, list selection edit mode, swipe actions row, recursive tree list, liststyle insetgrouped, listrowseparator tint.

List maps a collection to rows through a stable id, which is what lets SwiftUI animate inserts, removals, and reorders. Since iOS 15 it covers the full UITableView feature set: sections, selection, swipe actions, and separator styling.

Data, Sections, Trees

List(messages, id: \.id) { message in
  Text(message.content)
}

The id keypath must point at a stable property, such as a database key. Group rows with Section(header:) and ForEach per section. A dedicated initializer renders recursive data: pass a keypath to the optional children array and the list traverses the tree with disclosure arrows.

struct Tree<Value: Hashable>: Hashable {
  let value: Value
  var children: [Tree<Value>]? = nil
}

List(tree, id: \.value, children: \.children) { item in
  Text(String(item.value))
}

Selection

Selection works only in edit mode: pass a selection binding and put an EditButton in the toolbar. The binding's type picks the mode: Set<UUID> enables multi-select, an optional single id (UUID?) enables single-select.

@State private var selection: Set<UUID> = []

List(selection: $selection) {
  ForEach(messages, id: \.id) { message in
    Text(message.content)
  }
}
.toolbar { EditButton() }

Swipe Actions

Attach swipeActions to a row, per edge, with several buttons if needed. role: .destructive colors the delete red; tint colors the others. allowsFullSwipe: true lets a long swipe trigger the first action. iOS 15+.

Text(message.content)
  .swipeActions(edge: .trailing, allowsFullSwipe: true) {
    Button("Delete", role: .destructive) {
      messages.removeAll { $0.id == message.id }
    }
  }
  .swipeActions(edge: .leading, allowsFullSwipe: false) {
    Button("Favorite") { }.tint(.yellow)
    Button("Move") { }.tint(.green)
  }

Styling

Styles are plain, sidebar, inset, grouped, and insetGrouped (the default). The listStyle modifier propagates through the environment to every list below it. headerProminence(.increased) makes a section header bigger and bolder. Separator control is per row and per section: listRowSeparator, listRowSeparatorTint, listSectionSeparator, listItemTint.

Use this guidance in your coding agent

Install the Better Design MCP once. Your agent then loads this page with one call.

get-swiftui-guide({ topic: "swiftui-mastering-list" })
claude mcp add --scope user better-design --transport http https://better-design.com/api/mcp --header "Authorization: Bearer <YOUR_API_KEY>"
Browse related design systems