Tables
Table lets you present structured, tabular data with support for headers, filtering, striped styles, captions, and fine-grained row and column alignment.
Creating a Table
A table is composed of rows and columns, declared using builders. Each row represents a horizontal slice of data, and each column represents one cell within that row.
At its simplest, a table can be defined entirely inline:
Table {
TableRow {
"Ada Lovelace"
"12 Algorithm Way"
"London"
"UK"
}
TableRow {
"Grace Hopper"
"1 Compiler Lane"
"Arlington"
"Virginia"
}
TableRow {
"Alan Turing"
"43 Enigma Road"
"Manchester"
"UK"
}
}
| Ada Lovelace | 12 Algorithm Way | London | UK |
| Grace Hopper | 1 Compiler Lane | Arlington | Virginia |
| Alan Turing | 43 Enigma Road | Manchester | UK |
Rather than hardcoding rows, you can generate them from a collection using a closure. To clarify what each column represents, provide a header builder:
Table(developers) { developer in
TableRow {
developer.name
developer.email
developer.team
developer.location
}
} header: {
"Name"
"Email"
"Team"
"Location"
}
| Name | Team | Location | |
|---|---|---|---|
| Alex Morgan | alex.morgan@company.com | Platform | San Francisco |
| Jamie Chen | jamie.chen@company.com | Design Systems | New York |
| Riley Patel | riley.patel@company.com | Infrastructure | London |
| Taylor Brooks | taylor.brooks@company.com | Developer Experience | Remote |
Table Styles
Apply striped rows or columns using tableStyle(_:) to improve readability:
Table(projectMembers) { member in
TableRow {
member.name
member.role
member.primaryLanguage
member.yearsExperience
}
} header: {
"Name"
"Role"
"Language"
"Experience"
}
.tableStyle(.stripedRows)
.tableRowSeparator(.hidden)
| Name | Role | Language | Experience |
|---|---|---|---|
| Alex Morgan | Engineer | Swift | 6 |
| Jamie Chen | Designer | TypeScript | 5 |
| Riley Patel | SRE | Go | 8 |
Available styles include .stripedRows and .stripedColumns. Both optionally support rounded corners depending on your style configuration.
Filtering
To allow users to filter table rows, provide a filterTitle when creating the table:
Table(locations, filterTitle: "Filter locations") { location in
TableRow {
location.city
location.country
location.region
}
}
| San Francisco | USA | North America |
| London | UK | Europe |
| Tokyo | Japan | Asia |
| Sydney | Australia | Oceania |
This automatically inserts a search field above the table and filters rows based on visible text content.
Row Separators
You can customize the color of the separator that follows an individual row using tableRowSeparatorTint(_:):
Table {
TableRow {
"Server Status"
"Operational"
}
.tableRowSeparatorTint(.accent)
TableRow {
"Backup Status"
"Running"
}
}
| Server Status | Operational |
| Backup Status | Running |
Alignment and Spanning
Alignment
Rows align to the top-leading edge by default. To change alignment for individual columns, wrap content in TableColumn and apply a modifier:
Table {
TableRow {
ForEach(Alignment.allCases) { alignment in
TableColumn {
String(describing: alignment)
}
.alignment(alignment)
}
}
}
| Top Leading |
Top |
Top Trailing |
Leading |
Center |
Trailing |
Bottom Leading |
Bottom |
Bottom Trailing |
Column Spanning
Columns can span multiple slots using tableCellColumns(_:):
Table {
TableRow {
"Q1"
"Q2"
"Q3"
}
.multilineTextAlignment(.center)
TableRow {
TableColumn {
"Annual summary covering all quarters."
}
.tableCellColumns(3)
.alignment(.center)
}
}
.tableStyle(.stripedRows)
| Q1 | Q2 | Q3 |
| Annual summary covering all quarters. | ||
Captions and Accessibility
Tables can include an optional caption, which is displayed visually and announced by screen readers:
Table {
// rows
}
.caption("Deployment environment overview")