How it works
TableColumnCustomization is a value type that captures the user-driven state of a table's columns — their order, and which ones are hidden or shown. You hold it in your own storage and bind it to a Table so that the column layout a person arranges by dragging headers or toggling visibility survives across redraws and can be persisted or reset programmatically. Reach for it whenever a Table should remember how the reader rearranged it, rather than snapping back to the columns' declared order on every update.
Store the customization as observable state
TableColumnCustomization is generic over the table's row type, so you declare a single instance parameterized to your data and keep it where SwiftUI can observe writes to it. In the example it lives as
@State private var customization = TableColumnCustomization<Person>(), an empty value that represents the default, unmodified layout until the table mutates it.Bind it to the table with columnCustomization:
A Table accepts the customization through its
columnCustomization:parameter as a binding, giving the table read-and-write access to the stored layout. Passing$customizationtoTable(people, columnCustomization: $customization)is what lets header drags and the column-visibility menu flow back into your state instead of being lost.Identify each column with customizationID()
TableColumnCustomization tracks columns by a stable string key, so every column the user can reorder or hide must declare one with the
.customizationID()modifier. The.customizationID("name")and.customizationID("role")tags on the twoTableColumnvalues are the identifiers under which their order and visibility are recorded; a column without an ID can't participate in customization.Read and edit the recorded state
Because it is an ordinary value, you can inspect or drive the layout yourself between renders — querying or setting a column's visibility by its customization ID, or assigning a fresh
TableColumnCustomization<Person>()to restore the declared defaults. Thecustomizationvalue is the single source of truth theTableconsults each time it lays out its columns.
TableColumn("ID", value: \.id.uuidString).customizationID("id"), run it, drag the headers to reorder them, and watch the new arrangement stick because it's recorded in customization.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.
struct TableColumnCustomizationDemo: View {
struct Person: Identifiable {
let id = UUID()
let name: String
let role: String
}
@State private var customization = TableColumnCustomization<Person>()
private let people = [
Person(name: "Ada Lovelace", role: "Engineer"),
Person(name: "Alan Turing", role: "Designer")
]
var body: some View {
Table(people, columnCustomization: $customization) {
TableColumn("Name", value: \.name)
.customizationID("name")
TableColumn("Role", value: \.role)
.customizationID("role")
}
.padding()
}
}