<!-- https://svgrid.com/docs/help/columns/column-definitions/ - SvGrid documentation as markdown. Index of every page: https://svgrid.com/llms.txt -->

# 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 `ColumnDef`s - look at the [source](https://svgrid.com/demos/01-quick-start/) to see how each shape maps to a column behaviour:

> Live demo: Quick start - https://svgrid.com/demos/01-quick-start/

## Minimal

```ts
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`](https://github.com/sv-grid/sv-grid/blob/main/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:

```ts
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:

```ts
{ 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](https://svgrid.com/docs/help/cells/cell-components/).

## TypeScript

Pass the row type as the second generic; the column's `field` is then
checked against the row's keys:

```ts
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:

```ts
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.

```svelte
<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.

```svelte
<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

- [Updating definitions](https://svgrid.com/docs/help/columns/updating-definitions/)
- [Column state](https://svgrid.com/docs/help/columns/column-state/)
- [Custom header components](https://svgrid.com/docs/help/columns/custom-header-components/)
- Example: [`02-sort-filter-paginate.svelte`](https://svgrid.com/demos/02-sort-filter-paginate/)

---

SvGrid is the Svelte 5 data grid (`npm install @svgrid/grid`, MIT). This page: https://svgrid.com/docs/help/columns/column-definitions/ . All docs: https://svgrid.com/llms.txt
