TechnologiesSwiftUI

TableRowContent protocol

iOSmacOStvOSwatchOSvisionOS✓ renders

A type used to represent table rows.

How it works

TableRowContent is the protocol that describes the rows of a Table, just as View describes the contents of a view hierarchy. Every value you place inside a table's row builder — whether you write rows explicitly with TableRow or let the table generate them from a collection — conforms to TableRowContent, which ties each row to the data type it presents through its associated TableRowValue. You rarely name the protocol directly; instead you reach for it conceptually whenever you need to reason about what a table's body may contain, or when you build a reusable component that returns table rows from a @TableRowBuilder closure.

  1. Conform your row's value to Identifiable

    TableRowContent is parameterized by an associated TableRowValue, which must be Identifiable so the table can track, diff, and select individual rows. In the example, Person declares let id = UUID() to satisfy Identifiable, making it eligible to act as the row value carried by the table's content.

  2. Generate row content from a collection

    When you initialize a Table with a sequence of identifiable values, SwiftUI synthesizes the TableRowContent for you — one row per element, keyed by each element's id. Here Table(people) produces that row content automatically from the people array, so you never write a row literal even though each entry is backed by TableRowContent under the hood.

  3. Project values onto columns with key paths

    A table's columns read fields out of the row value, and the column's value key path is what binds a TableColumn to a property of the TableRowValue. The TableColumn("Name", value: \.name) and TableColumn("Role", value: \.role) lines pull name and role from each Person row, which is how the row content surfaces as cells.

  4. Compose rows in a @TableRowBuilder closure

    The trailing closure of Table is a @TableRowBuilder, a result builder whose result type is TableRowContent — the row-level analogue of @ViewBuilder. In the example the closure that holds the two TableColumn declarations is where row content is assembled, and any custom type returning some TableRowContent can be dropped into that same position.

Try it — Add a third Person(name: "Linus", role: "Hacker") to the people array and watch the table emit a new row with no other changes, since the row content is derived directly from the collection.

Example & preview

Press Run live & edit to compile it in your browser — then edit the Swift on the left and the preview re-renders live.

TableRowContent.swift
struct TableRowContentDemo: View {
    struct Person: Identifiable {
        let id = UUID()
        let name: String
        let role: String
    }
    let people = [
        Person(name: "Ada", role: "Engineer"),
        Person(name: "Grace", role: "Admiral"),
        Person(name: "Alan", role: "Theorist")
    ]
    var body: some View {
        Table(people) {
            TableColumn("Name", value: \.name)
            TableColumn("Role", value: \.role)
        }
        .padding()
    }
}
Live preview
Name Role Ada Engineer Grace Admiral Alan Theorist
Name Role Ada Engineer Grace Admiral Alan Theorist
swift → lexer → parser → sema → uiir → canvas Open in Studio ↗
What's new in SwiftUI 27 →