Home About

[TLDR] How to use Tables in SwiftUI

Written on September 7, 2023

This is the TLDR version of the article. View the full version here

Throughout this article I will assume the following structure is available.

struct User: Identifiable {
    let id: UUID

    let firstName: String
    let lastName: String
    let age: Int
    let favoriteColor: Color

    let createdAt: Date
    let updatedAt: Date
}

enum Color {
    case red, orange, yellow, green, blue, purple
}

Creating Tables

Table(users) {
  TableColumn("First Name", value: \.firstName)
  TableColumn("Last Name", value: \.lastName)

  TableColumn("Age") { user in
    Text(user.age.formatted())
  }
  .width(40)

  TableColumn("Color") { user in
    ColorView(color: user.favoriteColor)
  }
  .width(min: 55)

  TableColumn("Created") { user in
    Text(user.createdAt.formatted())
  }

  TableColumn("Updated") { user in
    Text(user.updatedAt.formatted())
  }
}

Row Control

Table(of: User.self) {
  //...Columns...
} rows: {
  ForEach(users) { user in
    TableRow(user)
  }
}

Selection

let users: [User]
@State private var selection: User.ID?

var body: some View {
  Table(users, selection: $selection) {
    //...Columns...
  }
}

Sorting

let users: [User]
private var presentedUsers: [User] {
  users.sorted(using: sortOrder)
}

@State private var sortOrder: [KeyPathComparator<User>] = [
  KeyPathComparator(\.firstName),
  KeyPathComparator(\.lastName),
]

var body: some View {
  Table(presentedUsers) {
    TableColumn("First Name", value: \.firstName)
    TableColumn("Last Name", value: \.lastName)

    TableColumn("Age", value: \.age) { user in
      Text(user.age.formatted())
    }
    .width(40)

    let colorComparator = KeyPathComparator(
      \User.favoriteColor,
      comparator: Color.Comparator()
    )
    TableColumn("Color", sortUsing: colorComparator) { user in
      ColorView(color: user.favoriteColor)
    }
    .width(min: 55)

    TableColumn("Created", value: \.createdAt) { user in
      Text(user.createdAt.formatted())
    }

    TableColumn("Updated", value: \.updatedAt) { user in
      Text(user.updatedAt.formatted())
    }
  }
}