Column Widths
Control how column widths are calculated to fit your content perfectly.
Column widths directly affect readability. Too narrow and text gets truncated — users see "John Sm..." instead of "John Smith". Too wide and columns waste space, forcing unnecessary horizontal scrolling.
SwiftDataTables calculates column widths automatically based on your content. You control how it calculates them — from simple fixed widths to intelligent content-aware measurement.
The Three Modes
Every column uses one of three width modes:
| Mode | How It Works | Best For |
|---|---|---|
.fixed(width:) | Every cell gets the exact width you specify | Known content, ID columns, buttons |
.fitContentText(strategy:) | Estimates width from text character counts | Large datasets with simple text cells |
.fitContentAutoLayout(sample:) | Measures cells using Auto Layout | Custom cells, complex layouts, small datasets |
Fixed Width
The simplest option. You specify the exact width in points, and every cell in that column gets that width.
var config = DataTableConfiguration()
config.columnWidthMode = .fixed(width: 120) // All columns 120pt wideWhen to use: ID columns, status badges, action buttons — anywhere the content width is predictable and consistent.
Auto Layout Measurement
The most accurate option. SwiftDataTables creates a sizing cell, configures it with your content, and asks Auto Layout how wide it needs to be (systemLayoutSizeFitting). This works with any cell complexity — multi-line text, images, nested stacks, Dynamic Type.
config.columnWidthMode = .fitContentAutoLayout(sample: .sampledMax(sampleSize: 50))The sample parameter controls how many cells are measured:
| Sample | Measures | Use Case |
|---|---|---|
.all | Every cell in the column | Small datasets (<100 rows) or exact sizing required |
.sampledMax(sampleSize: 50) | 50 evenly-distributed cells, uses the maximum | Good balance of accuracy and performance |
.percentile(0.95, sampleSize: 50) | 50 cells, uses 95th percentile width | Ignores extreme outliers that would over-widen columns |
For most apps, .sampledMax(sampleSize: 50) is the sweet spot — fast enough for large datasets, accurate enough to avoid truncation.
Text Estimation Strategies
For simple text cells (no images, no complex layouts), text estimation is faster than Auto Layout. It calculates width from character counts rather than measuring rendered cells.
config.columnWidthMode = .fitContentText(strategy: .hybrid(sampleSize: 100, averageCharWidth: 7))Six strategies are available, trading off accuracy vs performance:
| Strategy | How It Works | Performance | Accuracy |
|---|---|---|---|
.maxMeasured | Measures every cell's text, uses maximum | Slowest | Highest |
.sampledMax(sampleSize:) | Measures a sample, uses maximum | Fast | Good |
.percentileMeasured(percentile:, sampleSize:) | Measures a sample, uses Nth percentile | Fast | Good (ignores outliers) |
.estimatedAverage(averageCharWidth:) | charCount × avgCharWidth, averaged | Fastest | Moderate |
.hybrid(sampleSize:, averageCharWidth:) | Estimation validated against sample | Fast | Good |
.fixed(width:) | Explicit width, ignores content | Instant | N/A |
Choosing a Strategy
- Under 100 rows — Use
.maxMeasuredfor perfect accuracy - 100-10,000 rows — Use
.hybridor.sampledMaxfor balanced performance - 10,000+ rows — Use
.estimatedAveragefor speed, accept some truncation on outliers - Data with outliers — Use
.percentileMeasured(0.95, sampleSize: 100)to ignore the widest 5%
The averageCharWidth Parameter
Estimation strategies use averageCharWidth to convert character counts to points. The default is 7, which works for most system fonts at standard sizes.
- Monospace fonts — Characters are uniform width. Measure one character and use that exact value.
- Proportional fonts — Characters vary ("W" is wider than "i"). Use 7-8 for body text, adjust based on your font.
- Large text — Scale proportionally. If you're using 24pt font instead of 14pt, increase
averageCharWidthaccordingly.
Per-Column Overrides
Different columns often need different width strategies. An ID column should be fixed-width, while a description column should auto-size. Use columnWidthModeProvider to customize per column:
config.columnWidthModeProvider = { columnIndex in
switch columnIndex {
case 0: // ID column — always 60pt
return .fixed(width: 60)
case 1: // Name column — measure with Auto Layout
return .fitContentAutoLayout(sample: .sampledMax(sampleSize: 50))
case 4: // Actions column — fixed width for buttons
return .fixed(width: 100)
default:
return nil // Use the global columnWidthMode
}
}Returning nil tells the column to use the global columnWidthMode setting.
Minimum and Maximum Widths
Constrain calculated widths to a range:
config.minColumnWidth = 80 // Columns won't shrink below 80pt
config.maxColumnWidth = 300 // Columns won't grow beyond 300pt| Property | Default | Effect |
|---|---|---|
minColumnWidth | 70 | Prevents columns from becoming too narrow to read |
maxColumnWidth | nil (no limit) | Prevents columns from becoming excessively wide |
Header width always wins The header text (plus sort indicator) sets a minimum width that can exceed minColumnWidth. A column titled "Department" won't shrink narrower than that word, even if all data values are shorter.
Scale to Fill
By default, if your calculated column widths don't fill the table's frame, columns scale up proportionally to fill the space. This prevents awkward empty space on the right side.
// Default: columns expand to fill available width
config.shouldContentWidthScaleToFillFrame = true
// Disable: columns use their calculated widths exactly
config.shouldContentWidthScaleToFillFrame = falseWhen disabled, columns keep their calculated widths. If the total is less than the table width, empty space appears on the right. If the total exceeds the table width, horizontal scrolling is enabled.
Real-World Example
A typical configuration for a mixed table — some columns fixed, some auto-sized, with reasonable constraints:
var config = DataTableConfiguration()
// Global default: text estimation for performance
config.columnWidthMode = .fitContentText(strategy: .hybrid(sampleSize: 100, averageCharWidth: 7))
// Constraints
config.minColumnWidth = 60
config.maxColumnWidth = 250
// Per-column overrides
config.columnWidthModeProvider = { columnIndex in
switch columnIndex {
case 0: // Row number
return .fixed(width: 50)
case 5: // Description — needs Auto Layout for wrapping
return .fitContentAutoLayout(sample: .sampledMax(sampleSize: 30))
default:
return nil
}
}
let columns: [DataTableColumn<Product>] = [
.init("#") { String($0.rowNumber) },
.init("SKU", \.sku),
.init("Name", \.name),
.init("Category", \.category),
.init("Price", \.price) { String(format: "$%.2f", $0) },
.init("Description", \.description) // Uses Auto Layout override
]