Column API
Use this page when you need the exact meaning of a column field. For the higher-level setup flow, start with Define columns.
Main type
interface DatatableColumn<TData, TValue = unknown> {
id: string
header: string
order?: number
defaultVisible?: boolean
width?: number
minWidth?: number
maxWidth?: number
resizable?: boolean
accessorKey?: keyof TData
accessorFn?: (row: TData) => TValue
cell?: ColumnDef<TData, TValue>["cell"]
enableSorting?: boolean
sortingFn?: ColumnDef<TData, TValue>["sortingFn"]
showSortInHeader?: boolean
enableFiltering?: boolean
enableGlobalFilter?: boolean
filterType?: FilterType
filterOptions?: FilterOptions
enableGrouping?: boolean
groupingSpec?: ColumnGroupingSpec
meta?: {
displayName?: string
filterName?: string
filterIcon?: React.ComponentType<{ className?: string }>
[key: string]: unknown
}
}Identity and labels
id
Stable machine-readable column ID.
This is the contract key used by:
- filters
- sorting
- grouping
- saved views
- persisted current-view state
- URL state
- online query inputs
Do not derive it from visible text.
header
Primary visible column label in the shipped grid header.
meta.displayName
Optional friendlier display label for product surfaces that should not reuse the raw header text.
meta.filterName
Optional label override for filter UI.
meta.filterIcon
Optional custom icon for filter affordances.
Visibility and order
order
Initial relative column order.
Use it when the source order of your array should not be the rendered default.
defaultVisible
Whether the column starts visible.
Hidden-by-default columns can still be surfaced later through display options, views, or persisted state if your table exposes those controls.
Width and resizing
width
Initial resolved width in pixels.
minWidth
Minimum allowed width.
maxWidth
Maximum allowed width.
resizable
Per-column override for whether the user can resize this column.
Use fixed sizing for structural columns that should not be dragged into unusable widths.
Data access
accessorKey
Direct field access for simple columns.
{
id: "company",
accessorKey: "company",
header: "Company",
}Prefer this when the rendered value maps directly to a row property.
accessorFn
Derived value accessor.
{
id: "accountHealth",
header: "Health",
accessorFn: (row) => `${row.status}:${row.seats}`,
}Use this only when the column value is intentionally computed. In online mode, make sure your backend query semantics still match the column ID and intended sort/filter behavior.
cell
Custom cell renderer.
The table provides TanStack-style cell context in both local and online modes, so normal cell patterns still work when online rows are server-shaped.
For broader guidance, see:
Sorting fields
enableSorting
Whether the column participates in sorting.
sortingFn
TanStack-compatible local sorting function override.
Use this only when the default sort semantics for the accessed value are wrong for local mode.
showSortInHeader
Whether sort state should render in the header for this column.
This is useful when sorting is still active but should stay out of the primary header presentation.
Filtering fields
enableFiltering
Whether the column participates in column-filter workflows.
enableGlobalFilter
Whether the column is included in the shipped quick-search/global-search behavior.
See Add global search.
filterType
"text" | "number" | "date" | "boolean" | "text-list" | "id-list" | "custom"This controls the filter payload shape and the intended user query semantics.
Common uses:
text: names, titles, identifiersnumber: counts, amounts, scoresdate: machine-readable date fieldsboolean: yes/no statetext-list: finite visible labels such as status or planid-list: related entity IDs such as assignee or projectcustom: product-owned custom filter payload
filterOptions
Optional configuration for the selected filterType.
Option-list filters support a shared presentation hook:
renderOption?: (option: { value: string | boolean; label: string }) => React.ReactNodeUse renderOption when the built-in option editor should show richer rows, such as avatars, icons, color dots, or status badges. The selected filter payload still stores the option value; renderOption only changes presentation.
Text-list options
{
options: string[] | { value: string; label: string }[]
renderOption?: (option: { value: string; label: string }) => React.ReactNode
}ID-list options
{
options: { value: string; label: string }[]
isLoading?: boolean
emptyText?: string
searchPlaceholder?: string
renderOption?: (option: { value: string; label: string }) => React.ReactNode
}Boolean options
{
options?: [{ value: true; label: string }, { value: false; label: string }]
renderOption?: (option: { value: boolean; label: string }) => React.ReactNode
}Date options
{
presets?: ("today" | "yesterday" | "last7days" | "last30days" | "thisMonth" | "lastMonth")[]
}Reference note: the type system supports more filter shapes than every shipped filter UI currently exposes. Document the product surface you actually ship.
See:
Grouping fields
enableGrouping
Whether the column can be used in grouping controls.
groupingSpec
Controls how values group when raw values are not the right product bucket.
interface ColumnGroupingSpec {
supportsOffline?: boolean
supportsOnline?: boolean
variants: Record<string, GroupingVariant>
defaultVariant: string
}supportsOffline
Set to false when a grouping model should only be handled by your backend.
supportsOnline
Set to false when a grouping model only makes sense in local mode.
variants
Named grouping strategies.
type GroupingVariant =
| { kind: "raw"; emptyLabel?: string }
| { kind: "date_trunc"; granularity: "day" | "week" | "month" | "year"; emptyLabel?: string }
| { kind: "bucket"; buckets: GroupingBucket[]; emptyLabel?: string }Raw grouping
Groups by the raw value directly.
Date truncation
Useful for month, week, or year buckets built from a machine-readable date.
Buckets
Useful for numeric ranges such as seat tiers, deal size bands, or SLA buckets.
interface GroupingBucket {
id: string
label: string
min?: number
max?: number
}defaultVariant
The variant key used unless the grouping flow explicitly chooses another one.
See Add grouping.
Runtime column metadata
The source also defines a lower-level ColumnMetadata interface used inside the resolved table model:
interface ColumnMetadata {
width?: number
showSortInHeader?: boolean
isSticky?: boolean
isLastStickyColumn?: boolean
stickyLeftOffset?: number
filterType?: FilterType
isSpacer?: boolean
[key: string]: unknown
}This is mostly useful when extending internal rendering behavior on the copied source, not for normal table setup.
Practical reminders
- Keep column IDs stable over time.
- Choose filter and grouping semantics from the data model, not from the badge or cell styling.
- Treat
cellas a rendering seam, not a place to hide behavioral rules. - In online mode, remember that your backend still owns the real sorting, filtering, grouping, and facet behavior.