Column definitions
A ColumnDef tells SvGrid how to read a value out of a row, how to render it,
and which features apply to it. The grid below is built from a handful
of ColumnDefs - look at the source to see how each shape maps to a column behaviour:
Open the live example: Quick start (Getting Started)
Minimal
import type { ColumnDef } from '@svgrid/grid'
type Person = { firstName: string; age: number; status: string }
const columns: GridColumns<Person> = [
{ field: 'firstName', header: 'First name' },
{ field: 'age', header: 'Age' },
{ field: 'status', header: 'Status' },
]
Properties
| Property | Type | Purpose |
|---|---|---|
id |
string |
Stable column id. Required when you use fieldFn and no field. |
field |
keyof TData & string |
Reads row[key]. |
fieldFn |
(row) => unknown |
Computes the value. |
header |
string | (ctx) => unknown |
String, or a function returning a renderSnippet / renderComponent. |
cell |
(ctx) => unknown |
Same shape as header, for body cells. |
footer |
string | (ctx) => unknown |
Footer cell. |
editorType |
'text' | 'number' | 'date' | 'datetime' | 'checkbox' |
Inline editor type. |
format |
CellFormatConfig |
Built-in number, currency, percent, date, datetime formatters. |
formatter |
(ctx) => string |
Custom formatter - runs after field / fieldFn. |
columns |
ColumnDef[] |
Children - turns this column into a column group. |
width |
number |
Initial width in pixels (overrides the grid's columnWidth). |
See packages/grid/src/core.ts.
Accessor vs. fieldFn
field is the common case. Use fieldFn when the value is
computed or comes from a nested object:
const columns: GridColumns<Person> = [
{ field: 'firstName', header: 'First' },
{
id: 'fullName',
header: 'Full name',
fieldFn: (row) => `${row.firstName} ${row.lastName}`,
},
]
Whenever you use fieldFn you must supply an id - there is no string key
to derive one from.
Format vs. formatter vs. cell
| You want | Use |
|---|---|
| Locale-aware number / currency / percent / date | format |
| A custom string transformation | formatter |
| Custom HTML (avatars, pills, progress, sparklines) | cell with renderSnippet |
format is purely declarative and locale-aware - prefer it for anything
numeric or temporal:
{ field: 'salary', header: 'Salary',
format: { type: 'currency', currency: 'USD', options: { maximumFractionDigits: 0 } } }
{ field: 'joinedAt', header: 'Joined',
format: { type: 'date', pattern: 'y-m-d' } }
{ field: 'utilization', header: 'Utilization',
format: { type: 'percent', valueIsPercentPoints: true } } // 42 -> 42%
formatter runs after the accessor; the result is what gets displayed
(and what gets copied to the clipboard during cell selection).
cell is the most powerful - see Cell components.
TypeScript
Pass the row type as the second generic; the column's field is then
checked against the row's keys:
const columns: GridColumns<Person> = [
{ field: 'firstName' }, // ✅
// { field: 'first_name' } // ✗ compile error
]
The first generic is the feature set - derive it from tableFeatures so
feature-specific column properties light up:
const features = tableFeatures({ rowSortingFeature, columnFilteringFeature })
type Features = typeof features
const columns: ColumnDef<Features, Person>[] = [/* … */]
Alignment follows the data
align is inferred from the editor type when you leave it out, which is why
numbers land right without being told. Set it explicitly only when you disagree
- a right-aligned code, a centred status.
<script lang="ts">
import { SvGrid, type GridColumns, type SvGridApi } from '@svgrid/grid'
type Person = {
id: number
name: string
department: string
city: string
age: number
salary: number
}
const people: Person[] = [
{ id: 1, name: 'Ada Lovelace', department: 'Engineering', city: 'London', age: 36, salary: 142000 },
{ id: 2, name: 'Grace Hopper', department: 'Engineering', city: 'New York', age: 45, salary: 168000 },
{ id: 3, name: 'Linus Torvalds', department: 'Platform', city: 'Portland', age: 54, salary: 155000 },
{ id: 4, name: 'Radia Perlman', department: 'Networking', city: 'Seattle', age: 49, salary: 161000 },
{ id: 5, name: 'Barbara Liskov', department: 'Platform', city: 'Boston', age: 52, salary: 172000 },
]
const columns: GridColumns<Person> = [
{ field: 'name', header: 'Name', width: 190 },
{ field: 'city', header: 'City', width: 130, align: 'center' },
{ field: 'age', header: 'Age', width: 90, editorType: 'number' },
{ field: 'salary', header: 'Salary', width: 140, align: 'right',
format: { type: 'currency', currency: 'USD' } },
]
</script>
<SvGrid data={people} {columns} />
Per-column opt-outs
Turning a capability on at the grid level does not force it on every column.
sortable: false and filterable: false take a column out - useful for an
actions column, or a note nobody should sort by.
<script lang="ts">
import { SvGrid, type GridColumns, type SvGridApi } from '@svgrid/grid'
type Person = {
id: number
name: string
department: string
city: string
age: number
salary: number
}
const people: Person[] = [
{ id: 1, name: 'Ada Lovelace', department: 'Engineering', city: 'London', age: 36, salary: 142000 },
{ id: 2, name: 'Grace Hopper', department: 'Engineering', city: 'New York', age: 45, salary: 168000 },
{ id: 3, name: 'Linus Torvalds', department: 'Platform', city: 'Portland', age: 54, salary: 155000 },
{ id: 4, name: 'Radia Perlman', department: 'Networking', city: 'Seattle', age: 49, salary: 161000 },
{ id: 5, name: 'Barbara Liskov', department: 'Platform', city: 'Boston', age: 52, salary: 172000 },
]
const columns: GridColumns<Person> = [
{ field: 'name', header: 'Name', width: 190 },
{ field: 'department', header: 'Department', width: 160 },
// Sortable everywhere except here.
{ field: 'city', header: 'City', width: 140, sortable: false, filterable: false },
{ field: 'salary', header: 'Salary', width: 140,
format: { type: 'currency', currency: 'USD' } },
]
</script>
<SvGrid data={people} {columns} sortable filterable filterMode="row" />
See also
Live examples
- Quick start - A realistic 25-row × 9-column grid with sort, filter, selection, inline editing, and column resize all enabled.
- Sort, filter, paginate - Three most-asked-for features wired together against ~5k rows.
Related articles
- Column Definitions in SvGrid - Fields, Accessors, and Formatting - A practical look at how ColumnDef controls field binding, value resolution, sort behavior, and custom cell rendering in SvGrid.
- Multi-Level (Grouped) Column Headers in SvGrid - Band related columns under a shared parent header using SvGrid's nested column definition - how to nest, pin, combine with sorting and filtering, and when NOT to use grouping.
- A Custom Column Header Menu in SvGrid - Build a per-column header menu for sort, hide, pin, and custom actions using header snippets and your own dropdown component.