v2.0.3
This guide covers changes to the beta DataTable component. These APIs may continue to evolve before the stable release.
Overview
The DataTable column helper now supports two new properties that improve developer experience:
type - Automatically configures display formatting and alignment based on data type
editConfig - Consolidates cell editing configuration into a single, explicit opt-in property
These changes reflect our design philosophy of providing sensible defaults while maintaining full customization. Rather than requiring explicit configuration for common patterns, the new API infers reasonable defaults that you can override when needed.
Design Rationale
Why type?
Previously, configuring a currency column required setting multiple independent properties:
// Before: Manual configuration for each concern
createColumn("amount", {
headerLabel: "Amount",
align: "end",
renderCell: (value) => currencyFormatter(value),
});
These properties are conceptually related - a currency column should right-align and use currency formatting. The new type property captures this relationship:
// After: Single property sets sensible defaults
createColumn("amount", {
headerLabel: "Amount",
type: "currency", // Sets align: "end" and currencyFormatter automatically
});
Why editConfig?
The previous API scattered edit-related properties across the column definition:
// Before: Edit properties spread across the config
createColumn("status", {
headerLabel: "Status",
editMode: "select",
options: [...],
onChange: handleChange,
});
This made it unclear which properties were related and whether a column was editable. The new editConfig property makes the intent explicit:
// After: All edit concerns grouped together
createColumn("status", {
headerLabel: "Status",
editConfig: {
mode: "select",
options: [...],
onChange: handleChange,
},
});
Importantly, editing is now opt-in. Without editConfig, columns are read-only regardless of type.
Extensibility
This structure supports future enhancements without breaking changes:
- New column types (e.g.,
link, avatar, progress) can be added with appropriate defaults
- New edit modes (e.g.,
number with min/max/step, date picker) can include mode-specific options
- Edit-specific options (e.g.,
decimalDigits for number mode) live inside editConfig
Column Types Reference
Each type sets default values for align and renderCell:
| Type | Default Align | Default Formatter |
|---|
text | start | None (raw value) |
number | end | numberFormatter |
currency | end | currencyFormatter |
percent | end | percentFormatter |
date | end | dateFormatter |
dateTime | end | dateTimeFormatter |
time | end | timeFormatter |
boolean | start | booleanFormatter |
Using Type with Custom Options
For simple cases, pass the type as a string:
createColumn("amount", {
headerLabel: "Amount",
type: "currency",
});
To customize formatter options, pass an object:
createColumn("amount", {
headerLabel: "Amount",
type: {
type: "currency",
options: { currency: "EUR", locale: "de-DE" }
},
});
Overriding Type Defaults
Explicit properties always override type defaults:
createColumn("amount", {
headerLabel: "Amount",
type: "currency",
align: "start", // Overrides the default "end"
renderCell: (value) => `$${value.toFixed(0)}`, // Overrides currencyFormatter
});
EditConfig Reference
The editConfig property accepts an object with mode, onChange, and mode-specific options.
Text Mode
createColumn("name", {
headerLabel: "Name",
editConfig: {
mode: "text",
onChange: (value, rowId) => updateName(value, rowId),
},
});
Select Mode
createColumn("status", {
headerLabel: "Status",
editConfig: {
mode: "select",
options: [
{ value: "pending", label: "Pending" },
{ value: "active", label: "Active" },
{ value: "completed", label: "Completed" },
],
onChange: (value, rowId) => updateStatus(value, rowId),
},
});
Multiselect Mode
createColumn("tags", {
headerLabel: "Tags",
editConfig: {
mode: "multiselect",
options: [
{ value: "urgent", label: "Urgent" },
{ value: "reviewed", label: "Reviewed" },
],
onChange: (value, rowId) => updateTags(value, rowId),
},
});
Migration Guide
Display-Only Columns
No changes required. Optionally add type for automatic formatting:
// Before
createColumn("amount", {
headerLabel: "Amount",
renderCell: (value) => currencyFormatter(value),
});
// After (optional improvement)
createColumn("amount", {
headerLabel: "Amount",
type: "currency",
});
Editable Columns
Move editMode, onChange, and options into editConfig:
// Before
createColumn("name", {
headerLabel: "Name",
editMode: "text",
onChange: handleChange,
});
// After
createColumn("name", {
headerLabel: "Name",
editConfig: {
mode: "text",
onChange: handleChange,
},
});
For select/multiselect columns:
// Before
createColumn("status", {
headerLabel: "Status",
editMode: "select",
options: statusOptions,
onChange: handleChange,
});
// After
createColumn("status", {
headerLabel: "Status",
editConfig: {
mode: "select",
options: statusOptions,
onChange: handleChange,
},
});
Deprecation Timeline
The following props show deprecation warnings in development:
editMode - Use editConfig.mode instead
onChange (top-level) - Use editConfig.onChange instead
options (top-level) - Use editConfig.options instead
Existing code continues to work but will log console warnings to guide migration. TypeScript also marks these props with @deprecated JSDoc comments.
New Exports
The following types are now exported from @servicetitan/anvil2:
ColumnType - Union of column type literals
ColumnTypeConfig - Type configuration (string or object with options)
EditConfig, TextEditConfig, SelectEditConfig, MultiselectEditConfig - Edit configuration types
getColumnTypeDefaults(), resolveColumnTypeConfig() - Utility functions for working with column types