Reusable column presets for consistent configuration.
Column types are reusable presets that define common column configurations. They promote consistency and reduce duplication by allowing you to reference predefined column settings.
type DataTableColumnTypes<TData> = Record<
string,
Partial<DataTableColumnDef<TData, any>>
>;const columnTypes: DataTableColumnTypes<Order> = {
currency: {
size: 120,
meta: {
cellAlign: 'right',
valueFormatter: (value) => `$${value.toFixed(2)}`,
},
},
};
// Use in column definition
{
accessorKey: 'price',
header: 'Price',
type: 'currency',
}const columnTypes: DataTableColumnTypes<User> = {
email: {
size: 250,
meta: {
filterType: 'text',
truncate: true,
},
},
};const columnTypes: DataTableColumnTypes<Order> = {
currency: {
size: 120,
meta: {
headerAlign: 'right',
cellAlign: 'right',
cellClassName: 'font-mono',
filterType: 'number',
aggregationFn: 'sum',
valueFormatter: (value) =>
new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
}).format(value as number),
},
},
};const columnTypes: DataTableColumnTypes<Data> = {
percentage: {
size: 100,
meta: {
headerAlign: 'right',
cellAlign: 'right',
filterType: 'number',
aggregationFn: 'avg',
valueFormatter: (value) => `${value}%`,
cellClassRules: {
'text-green-600': (value) => value > 75,
'text-yellow-600': (value) => value >= 50 && value <= 75,
'text-red-600': (value) => value < 50,
},
},
},
};const columnTypes: DataTableColumnTypes<Event> = {
date: {
size: 140,
meta: {
filterType: 'date',
valueFormatter: (value) =>
new Date(value as string).toLocaleDateString('en-US'),
},
},
};const columnTypes: DataTableColumnTypes<Task> = {
badge: {
size: 120,
meta: {
headerAlign: 'center',
cellAlign: 'center',
filterType: 'select',
},
cell: ({ getValue }) => {
const value = getValue() as string;
return <Badge>{value}</Badge>;
},
},
};const columnTypes: DataTableColumnTypes<User> = {
boolean: {
size: 100,
meta: {
headerAlign: 'center',
cellAlign: 'center',
filterType: 'boolean',
},
cell: ({ getValue }) => {
const value = getValue() as boolean;
return value ? '✓' : '✗';
},
},
};{
accessorKey: 'price',
header: 'Price',
type: 'currency',
}Types are merged in order, with later types overriding earlier ones.
const columnTypes = {
currency: { size: 120 },
editable: { meta: { editable: true } },
};
// Merges both types
{
accessorKey: 'price',
header: 'Price',
type: ['currency', 'editable'],
}Column-specific properties override type properties.
{
accessorKey: 'discount',
header: 'Discount',
type: 'percentage',
size: 150, // Overrides type's size
}const columnTypes: DataTableColumnTypes<Order> = {
currency: {
size: 120,
meta: {
headerAlign: 'right',
cellAlign: 'right',
cellClassName: 'font-mono',
filterType: 'number',
aggregationFn: 'sum',
valueFormatter: (value) =>
new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
}).format(value as number),
},
},
percentage: {
size: 100,
meta: {
headerAlign: 'right',
cellAlign: 'right',
filterType: 'number',
aggregationFn: 'avg',
valueFormatter: (value) => `${value}%`,
},
},
date: {
size: 140,
meta: {
filterType: 'date',
valueFormatter: (value) =>
new Date(value as string).toLocaleDateString('en-US'),
},
},
status: {
size: 120,
meta: {
headerAlign: 'center',
cellAlign: 'center',
filterType: 'select',
},
cell: ({ getValue }) => {
const status = getValue() as string;
return <Badge variant={status}>{status}</Badge>;
},
},
actions: {
size: 100,
enableSorting: false,
enableHiding: false,
enableResizing: false,
meta: {
headerAlign: 'center',
cellAlign: 'center',
},
},
editable: {
meta: {
editable: true,
editType: 'text',
},
},
numeric: {
meta: {
headerAlign: 'right',
cellAlign: 'right',
cellClassName: 'font-mono',
filterType: 'number',
enableFilterOperators: true,
},
},
};
<DataTable columnTypes={columnTypes} columns={columns} {...} />const columns: DataTableColumnDef<Order>[] = [
{
accessorKey: 'id',
header: 'ID',
size: 80,
enableSorting: false,
},
{
accessorKey: 'customer',
header: 'Customer',
type: 'editable',
},
{
accessorKey: 'total',
header: 'Total',
type: 'currency',
},
{
accessorKey: 'discount',
header: 'Discount',
type: 'percentage',
},
{
accessorKey: 'date',
header: 'Order Date',
type: 'date',
},
{
accessorKey: 'status',
header: 'Status',
type: 'status',
},
{
id: 'actions',
header: 'Actions',
type: 'actions',
cell: ({ row }) => <ActionsMenu row={row} />,
},
];Column types provide:
const columnTypes = {
integer: {
meta: {
cellAlign: 'right',
filterType: 'number',
valueFormatter: (value) => value?.toLocaleString(),
},
},
decimal: {
meta: {
cellAlign: 'right',
filterType: 'number',
valueFormatter: (value) => value?.toFixed(2),
},
},
};const columnTypes = {
link: {
meta: {
truncate: true,
},
cell: ({ getValue, row }) => {
const url = getValue() as string;
return <a href={url} className="text-blue-600 hover:underline">{url}</a>;
},
},
};const columnTypes = {
longText: {
size: 300,
meta: {
wrapText: true,
autoHeight: true,
truncate: false,
},
},
};type Order = {
id: string;
total: number;
discount: number;
status: 'pending' | 'completed';
};
const columnTypes: DataTableColumnTypes<Order> = {
currency: {
// Type-safe configuration
meta: {
valueFormatter: (value: number) => `$${value.toFixed(2)}`,
},
},
};