TechnologiesSwiftUI

TableRowBuilder struct

iOSmacOStvOSwatchOSvisionOS✓ renders

A result builder that creates table row content from closures.

How it works

TableRowBuilder is the result builder that assembles the rows of a Table. Whenever you write a row-producing closure, SwiftUI applies TableRowBuilder behind the scenes to combine each row expression into a single TableRowContent value the table can lay out. You rarely name it directly — it's the @resultBuilder attached to the parameters that take table rows — but it's what lets you list rows declaratively, mix static and dynamic rows, and apply conditionals without manual collection wrapping. Reach for an understanding of it whenever you build a Table and need to know why its trailing closures accept plain row content the way ViewBuilder accepts views.

  1. Let the builder collect a column-driven table's rows

    When you initialize a Table over a data collection, you don't write rows at all — TableRowBuilder is the closure type that supplies a row per element automatically, while the closure you write describes columns. In the example, Table(people) hands each Person to the builder, which emits one row for Alex, Sam, and Jordan from the people array.

  2. Pair the builder's rows with TableColumn definitions

    Each row the builder produces is filled by the TableColumn values declared in the table's content closure, which map a key path to a cell. Here TableColumn("Name", value: \.name) and TableColumn("Role", value: \.role) define the two cells every builder-generated row renders, so value: \.name and value: \.role pull the text shown in each row.

  3. Require Identifiable rows so the builder can track them

    The builder needs a stable identity for every row it assembles so SwiftUI can diff and animate updates. That's why the row data conforms to Identifiable; in the example struct Person: Identifiable supplies an id via let id = UUID(), and the builder keys each emitted row on that identity.

  4. Switch to an explicit builder closure for static rows

    When you want fixed rows instead of a collection, you write them directly inside Table { ... } and TableRowBuilder combines those TableRow expressions — supporting if/switch and multiple statements just like ViewBuilder. The column-driven form shown with Table(people) is the common case, but the same builder powers the explicit-row form by accepting one or more TableRow values.

Try it — Add a third TableColumn("ID", value: \.name) inside the Table(people) closure to watch every builder-generated row gain a cell, then remove a Person from people and see the builder drop that row.

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.

TableRowBuilder.swift
struct TableRowBuilderDemo: View {
    struct Person: Identifiable {
        let id = UUID()
        let name: String
        let role: String
    }
    let people = [
        Person(name: "Alex", role: "Designer"),
        Person(name: "Sam", role: "Engineer"),
        Person(name: "Jordan", role: "Manager")
    ]
    var body: some View {
        Table(people) {
            TableColumn("Name", value: \.name)
            TableColumn("Role", value: \.role)
        }
        .padding()
    }
}
Live preview
Name Role Alex Designer Sam Engineer Jordan Manager
Name Role Alex Designer Sam Engineer Jordan Manager
swift → lexer → parser → sema → uiir → canvas Open in Studio ↗
What's new in SwiftUI 27 →