TablixJS Column Formatting System
July 22, 2025 ยท View on GitHub
The TablixJS Column Formatting System provides a flexible, lightweight, and fully optional way to format cell values using the modern Intl APIs. This system is inspired by Handsontable cell formats but designed to be more flexible and lightweight.
Overview
Key Features
- Flexible formatting: Text, date, currency, number, and percentage formats
- Optional locale support: Uses browser default or specify custom locale
- Intl API integration: Leverages native browser formatting capabilities
- Custom renderer priority: User renderers can override or use formatted values
- Performance optimized: Formatters are compiled and cached once per column
- Graceful error handling: Invalid data doesn't break the table
- No defaults: Pure behavior - values unchanged unless explicitly formatted
- Extensible design: Ready for future custom format types
Quick Start
import Table from './src/core/Table.js';
const table = new Table('#container', {
data: [
{ name: 'Alice', salary: 95000, joinDate: '2022-03-15', bonus: 0.15 }
],
columns: [
{ name: 'name', title: 'Employee' }, // Raw value
{ name: 'salary', title: 'Salary', format: 'currency', currency: 'USD' },
{ name: 'joinDate', title: 'Join Date', format: 'date' },
{ name: 'bonus', title: 'Bonus', format: 'percent' }
]
});
Column Configuration
Basic Structure
{
name: 'columnName', // Required: data property name
title: 'Display Name', // Optional: header display text
format: 'formatType', // Optional: format type
locale: 'en-US', // Optional: locale for formatting
formatOptions: { ... }, // Optional: Intl API options
currency: 'USD', // Required for currency format
renderer: (value, row, formattedValue) => { ... } // Optional: custom renderer
}
Format Types
1. Text Format
Basic string conversion with null/undefined handling.
{ name: 'description', title: 'Description', format: 'text' }
2. Number Format
Uses Intl.NumberFormat for numeric values.
// Basic number
{ name: 'rating', format: 'number' }
// With decimal places
{
name: 'score',
format: 'number',
formatOptions: {
minimumFractionDigits: 2,
maximumFractionDigits: 2
}
}
// With locale
{
name: 'population',
format: 'number',
locale: 'de-DE',
formatOptions: { useGrouping: true }
}
3. Currency Format
Uses Intl.NumberFormat with currency style.
// Basic USD currency
{
name: 'salary',
format: 'currency',
currency: 'USD'
}
// EUR with German locale
{
name: 'price',
format: 'currency',
currency: 'EUR',
locale: 'de-DE'
}
// Custom options
{
name: 'budget',
format: 'currency',
currency: 'GBP',
locale: 'en-GB',
formatOptions: {
minimumFractionDigits: 0,
maximumFractionDigits: 0
}
}
4. Date Format
Uses Intl.DateTimeFormat for date/time values.
// Basic date
{ name: 'joinDate', format: 'date' }
// Short date style
{
name: 'createdAt',
format: 'date',
formatOptions: { dateStyle: 'short' }
}
// Custom format
{
name: 'updatedAt',
format: 'date',
locale: 'fr-FR',
formatOptions: {
year: 'numeric',
month: 'long',
day: '2-digit',
weekday: 'long'
}
}
// Date and time
{
name: 'timestamp',
format: 'date',
formatOptions: {
dateStyle: 'short',
timeStyle: 'medium'
}
}
5. Percentage Format
Uses Intl.NumberFormat with percent style.
// Basic percentage (0.15 โ 15%)
{ name: 'bonus', format: 'percent' }
// With decimals
{
name: 'commission',
format: 'percent',
formatOptions: { minimumFractionDigits: 2 }
}
// With locale
{
name: 'growth',
format: 'percent',
locale: 'de-DE',
formatOptions: { signDisplay: 'always' }
}
Custom Renderers
Custom renderers have priority over formatting but can use formatted values.
Renderer Function Signature
renderer: (value, row, formattedValue) => {
// value: raw cell value
// row: complete row object
// formattedValue: formatted value (if format is specified)
return 'HTML string or text';
}
Examples
Using Formatted Value
{
name: 'salary',
format: 'currency',
currency: 'USD',
renderer: (value, row, formattedValue) => {
const color = value >= 80000 ? 'green' : 'red';
return `<span style="color: ${color}">${formattedValue}</span>`;
}
}
Completely Custom
{
name: 'status',
renderer: (value) => {
return value ? 'Active' : 'Inactive';
}
}
Using Row Context
{
name: 'fullName',
renderer: (value, row) => {
return `${row.firstName} ${row.lastName}`;
}
}
Internationalization
Locale Support
- Default: Uses browser's default locale
- Custom: Specify any valid locale string
- Examples:
'en-US','de-DE','fr-FR','ja-JP','ar-SA'
Format Options
All formatOptions are passed directly to the respective Intl API:
DateTimeFormat Options
formatOptions: {
dateStyle: 'full' | 'long' | 'medium' | 'short',
timeStyle: 'full' | 'long' | 'medium' | 'short',
year: 'numeric' | '2-digit',
month: 'numeric' | '2-digit' | 'long' | 'short' | 'narrow',
day: 'numeric' | '2-digit',
weekday: 'long' | 'short' | 'narrow',
hour: 'numeric' | '2-digit',
minute: 'numeric' | '2-digit',
second: 'numeric' | '2-digit',
timeZone: 'UTC' | 'America/New_York' | ...
}
NumberFormat Options
formatOptions: {
minimumFractionDigits: 0,
maximumFractionDigits: 3,
minimumSignificantDigits: 1,
maximumSignificantDigits: 21,
useGrouping: true,
signDisplay: 'auto' | 'never' | 'always' | 'exceptZero'
}
Performance
Optimization Features
- Formatter Caching: Compiled once per column, reused for all rows
- Lazy Compilation: Only creates formatters for columns with
formatspecified - Error Resilience: Invalid data doesn't break formatting for other cells
Best Practices
- Use appropriate format types: Don't use
currencyfor simple numbers - Minimize formatOptions: Only specify needed options
- Cache heavy renderers: For complex custom renderers, consider memoization
- Test with large datasets: Verify performance with your expected data size
Error Handling
The formatting system gracefully handles various error conditions:
Invalid Data Types
// These won't break the table:
{ date: 'invalid-date', number: 'not-a-number', currency: null }
Unsupported Formats
// Warns and falls back to raw value:
{ name: 'field', format: 'unsupported-format' }
Missing Required Properties
// Currency without currency code:
{ name: 'price', format: 'currency' } // Will show warning
๐ฎ Extensibility
The system is designed for future extension:
Future Custom Formats (Conceptual)
// Future API for custom formats:
table.columnManager.registerFormat('filesize', (column) => {
return (value) => {
// Custom formatting logic
return formatFileSize(value);
};
});
// Usage:
{ name: 'fileSize', format: 'filesize' }
Plugin Architecture
The modular design allows for future plugins that could add:
- Custom format types
- Advanced formatting rules
- Conditional formatting
- Template-based formatting
Real-World Examples
Employee Table
const employeeTable = new Table('#employees', {
data: employees,
columns: [
{ name: 'id', title: 'ID' },
{ name: 'name', title: 'Employee Name' },
{ name: 'department', title: 'Department' },
{
name: 'salary',
title: 'Annual Salary',
format: 'currency',
currency: 'USD',
formatOptions: { minimumFractionDigits: 0 }
},
{
name: 'bonus',
title: 'Bonus Rate',
format: 'percent',
formatOptions: { minimumFractionDigits: 1 }
},
{
name: 'joinDate',
title: 'Hire Date',
format: 'date',
formatOptions: {
year: 'numeric',
month: 'short',
day: '2-digit'
}
},
{
name: 'rating',
title: 'Performance',
format: 'number',
formatOptions: { minimumFractionDigits: 1, maximumFractionDigits: 1 }
}
]
});
Financial Dashboard
const financialTable = new Table('#financial', {
data: transactions,
columns: [
{ name: 'date', title: 'Date', format: 'date', formatOptions: { dateStyle: 'short' } },
{ name: 'description', title: 'Description' },
{
name: 'amount',
title: 'Amount',
format: 'currency',
currency: 'EUR',
locale: 'de-DE',
renderer: (value, row, formattedValue) => {
const color = value >= 0 ? 'green' : 'red';
return `<span style="color: ${color}">${formattedValue}</span>`;
}
},
{
name: 'tax',
title: 'Tax Rate',
format: 'percent',
locale: 'de-DE'
}
]
});
Testing
Test your formatting with various data types:
const testData = [
{ value: 123.456, date: '2023-12-25', currency: 50000 },
{ value: null, date: null, currency: null },
{ value: 'invalid', date: 'invalid-date', currency: 'not-number' },
{ value: 0, date: new Date(), currency: 0 }
];
API Reference
ColumnManager Methods
initializeColumns(columns)
Initialize columns and compile formatters.
formatCellValue(columnName, value, row)
Format a cell value for display.
getColumn(columnName)
Get column definition by name.
getColumns()
Get all column definitions.
getSupportedFormats()
Get array of supported format types.
Format-Specific Options
See the Intl documentation for complete options:
This formatting system integrates seamlessly with TablixJS's existing features including sorting, pagination, and event hooks.