TechnologiesSwiftUI

TableColumnBuilder struct

iOSmacOStvOSwatchOSvisionOS✓ renders

A result builder that creates table column content from closures.

How it works

TableColumnBuilder is the result builder that assembles the columns you list inside a Table. Whenever you write a sequence of TableColumn declarations in a table's content closure, the compiler hands them to TableColumnBuilder, which gathers them into the single column collection the table renders left to right. You rarely name this type directly — it is the @resultBuilder attached to the column closure parameter — but it is what lets you describe a table's structure declaratively, one column per statement, instead of constructing an array by hand. Reach for an understanding of it whenever you need to know which column expressions are valid in that closure and how they combine.

  1. List columns in the table's content closure

    The closure you pass to Table is annotated with @TableColumnBuilder, so each statement you write is treated as one column rather than ordinary imperative code. In the example, the two TableColumn lines inside Table(people) { ... } are collected by the builder and become the table's Name and Role columns in the order written.

  2. Supply each column as a TableColumn value

    TableColumnBuilder accepts TableColumn values as its building blocks; each one binds a column title to the content drawn for every row. Here TableColumn("Name") provides a view-building closure that receives a person and returns Text(person.name).bold(), while TableColumn("Role", value: \.role) uses the key-path form to display the role string directly.

  3. Mix value-based and content-based columns freely

    Because the builder only requires that each statement produce a column, you can combine the custom-content initializer and the key-path value: initializer in the same closure. The Name column builds a styled Text per row, and the Role column derives its cells straight from \.role — both flow through TableColumnBuilder into one column set.

  4. Rely on the row type tying the columns together

    Every column in a builder closure must agree on the table's row element so the builder can type-check the collection as a whole. The Table(people) over Person values fixes that element type, which is why each TableColumn here can read person.name and the \.role key path against Person.

Try it — Add a third line TableColumn("ID") { person in Text(person.id.uuidString) } beside the existing TableColumn declarations to see the builder absorb a new column into the same Table with no other changes.

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.

TableColumnBuilder.swift
struct TableColumnBuilderDemo: View {
    struct Person: Identifiable {
        let id = UUID()
        let name: String
        let role: String
    }

    let people = [
        Person(name: "Ada Lovelace", role: "Engineer"),
        Person(name: "Alan Turing", role: "Scientist"),
        Person(name: "Grace Hopper", role: "Admiral")
    ]

    var body: some View {
        Table(people) {
            TableColumn("Name") { person in
                Text(person.name).bold()
            }
            TableColumn("Role", value: \.role)
        }
        .padding()
    }
}
Live preview
Name Role Ada Lovelace Engineer Alan Turing Scientist Grace Hopper Admiral
Name Role Ada Lovelace Engineer Alan Turing Scientist Grace Hopper Admiral
swift → lexer → parser → sema → uiir → canvas Open in Studio ↗
What's new in SwiftUI 27 →