Data Export
Export table data to CSV and Excel with custom formatting and transformations
Data Export
Export your table data to CSV and Excel formats with powerful transformation and formatting capabilities.
Basic Export Setup
Create Export Configuration
import { useMemo } from "react";
export function useExportConfig() {
const columnMapping = useMemo(() => ({
id: "User ID",
name: "Full Name",
email: "Email Address",
age: "Age",
created_at: "Registration Date",
}), []);
const headers = useMemo(() => [
"id",
"name",
"email",
"age",
"created_at",
], []);
const columnWidths = useMemo(() => [
{ wch: 10 }, // ID
{ wch: 25 }, // Name
{ wch: 30 }, // Email
{ wch: 10 }, // Age
{ wch: 20 }, // Created At
], []);
return {
columnMapping,
headers,
columnWidths,
entityName: "users", // Used in filename: users_2024-01-15.xlsx
};
}Add to DataTable
import { useExportConfig } from "./utils/config";
<DataTable
getColumns={getColumns}
fetchDataFn={useUsersData}
exportConfig={useExportConfig()} // Add export config
idField="id"
/>Result
✅ Export button appears in toolbar
✅ Downloads as users_2024-01-15.xlsx or .csv
✅ Columns have readable headers
✅ Proper column widths in Excel
Export Configuration Options
Column Mapping
Maps API field names to human-readable headers:
columnMapping: {
id: "Customer ID", // id → "Customer ID"
created_at: "Join Date", // created_at → "Join Date"
total_spent: "Lifetime Value", // total_spent → "Lifetime Value"
}Headers Array
Specifies which columns to export and their order:
headers: [
"id",
"name",
"email",
"age",
"created_at",
// Columns not listed won't be exported
]Column Widths (Excel Only)
Set column widths for Excel exports:
columnWidths: [
{ wch: 10 }, // 10 characters wide
{ wch: 25 }, // 25 characters wide
{ wch: 30 }, // 30 characters wide
]Width is in characters (wch). Order matches headers array.
Entity Name
Used in the exported filename:
entityName: "customers"
// Downloads as: customers_2024-01-15.xlsxData Transformation
Transform data before export to format values or add calculated columns.
Basic Formatting
import { DataTransformFunction } from "@/components/data-table/utils/export-utils";
import { formatTimestampToReadable, formatCurrency } from "@/utils/format";
const transformFunction: DataTransformFunction<User> = (row: User) => ({
...row,
// Format dates
created_at: formatTimestampToReadable(row.created_at),
// "2024-01-15T10:30:00Z" → "01/15/2024 10:30 AM"
// Format currency
total_spent: formatCurrency(row.total_spent),
// "1234.56" → "$1,234.56"
// Format phone numbers
phone: formatPhoneNumber(row.phone),
// "5551234567" → "(555) 123-4567"
});Adding Calculated Columns
Add new columns that don't exist in your data:
const enhancedTransform: DataTransformFunction<User> = (row: User) => {
const spentAmount = parseFloat(row.total_spent) || 0;
const currentYear = new Date().getFullYear();
const joinYear = new Date(row.created_at).getFullYear();
return {
...row,
// Format existing columns
created_at: formatTimestampToReadable(row.created_at),
total_spent: formatCurrency(row.total_spent),
// NEW calculated columns
customer_tier: spentAmount > 2000 ? "PREMIUM" :
spentAmount > 1000 ? "GOLD" :
spentAmount > 500 ? "SILVER" : "BRONZE",
years_active: currentYear - joinYear,
spending_category: spentAmount > 1000 ? "HIGH_SPENDER" :
spentAmount > 500 ? "MEDIUM_SPENDER" :
"LOW_SPENDER",
risk_level: row.order_count < 2 ? "HIGH_RISK" : "LOW_RISK",
};
};Include New Columns in Export
export function useExportConfig() {
return {
headers: [
// Original columns
"id", "name", "email", "phone", "created_at", "total_spent",
// NEW calculated columns
"customer_tier", "years_active", "spending_category", "risk_level"
],
columnMapping: {
// Original columns
id: "Customer ID",
name: "Full Name",
email: "Email",
phone: "Phone",
created_at: "Join Date",
total_spent: "Total Spent",
// NEW column headers
customer_tier: "Tier",
years_active: "Years Active",
spending_category: "Spending Category",
risk_level: "Risk Assessment",
},
transformFunction: enhancedTransform, // Apply transformation
entityName: "customers"
};
}Export Result
Your exported file will include:
Customer ID | Full Name | Email | Phone | Join Date | Total Spent | Tier | Years Active | Spending Category | Risk Assessment
1 | John Doe | john@example.com | (555) 123-4567 | 01/15/2023 10:30 AM | $2,450.75 | PREMIUM | 2 | HIGH_SPENDER | LOW_RISKAvailable Formatting Functions
Built-in utilities from /utils/format.ts:
| Function | Input | Output |
|---|---|---|
formatTimestampToReadable() | "2024-01-15T10:30:00Z" | "01/15/2024 10:30 AM" |
formatCurrency() | "1234.56" | "$1,234.56" |
formatPhoneNumber() | "5551234567" | "(555) 123-4567" |
formatToTitleCase() | "john doe" | "John Doe" |
formatBoolean() | true | "Yes" |
formatNumber() | 1234567 | "1,234,567" |
formatTruncatedText() | "Long text...", 20 | "Long text..." |
Controlling Export Columns
Hidden Columns
Hidden columns are automatically excluded from export:
// User hides "Email" column via column visibility toggle
// Export will not include email, only visible columnsAllow New Columns
Control whether transform function's new columns are exported:
config={{
allowExportNewColumns: true, // Include calculated columns (default)
// or
allowExportNewColumns: false, // Strict mode - visible columns only
}}When true:
- ✅ Exports visible table columns
- ✅ Exports new columns from transform function
- ❌ Excludes hidden table columns
When false:
- ✅ Exports visible table columns only
- ❌ Excludes hidden table columns
- ❌ Excludes new columns from transform function
Export Modes
Export Current Page
Export only the rows visible on current page:
// User clicks: "Export Current Page"
// Exports 10-20 rows (depending on page size)Export All Selected
Export all selected rows across all pages:
// User selects rows on pages 1, 3, and 5
// Clicks: "Export Selected"
// Exports only selected rows, regardless of pageExport All Data
Export the entire dataset:
// User clicks: "Export All"
// Fetches and exports all rows (respects current filters/search)Case Format Support
Export preserves your API's case format:
Snake_case API
// API Response: { user_name: "John", created_at: "..." }
headers: ["id", "user_name", "created_at"]
columnMapping: {
user_name: "Full Name", // ✅ Uses snake_case
created_at: "Registration",
}CamelCase API
// API Response: { userName: "John", createdAt: "..." }
headers: ["id", "userName", "createdAt"]
columnMapping: {
userName: "Full Name", // ✅ Uses camelCase
createdAt: "Registration",
}Export with Subrows
When using hierarchical data:
Flatten Subrows (Default)
exportConfig={{
// ... other options
flatten: true, // Each row (parent + children) becomes separate export row
}}Result:
Order # | Product | Quantity
ORD-001 | Widget A | 2
ORD-001 | Widget B | 1
ORD-002 | Gadget C | 3Parent Rows Only
exportConfig={{
// ... other options
flatten: false, // Export only parent rows
}}Result:
Order # | Product | Quantity
ORD-001 | Widget A | 2
ORD-002 | Gadget C | 3Complete Example
import { useMemo } from "react";
import { DataTransformFunction } from "@/components/data-table/utils/export-utils";
import { formatTimestampToReadable, formatCurrency } from "@/utils/format";
import { User } from "../schema";
const transformData: DataTransformFunction<User> = (row: User) => {
const spentAmount = parseFloat(row.total_spent) || 0;
return {
...row,
// Format existing fields
created_at: formatTimestampToReadable(row.created_at),
total_spent: formatCurrency(row.total_spent),
phone: formatPhoneNumber(row.phone),
// Add calculated fields
customer_tier: spentAmount > 2000 ? "PREMIUM" :
spentAmount > 1000 ? "GOLD" :
spentAmount > 500 ? "SILVER" : "BRONZE",
years_active: new Date().getFullYear() - new Date(row.created_at).getFullYear(),
};
};
export function useExportConfig() {
const headers = useMemo(() => [
"id",
"name",
"email",
"phone",
"age",
"created_at",
"order_count",
"total_spent",
"customer_tier",
"years_active",
], []);
const columnMapping = useMemo(() => ({
id: "Customer ID",
name: "Full Name",
email: "Email Address",
phone: "Phone Number",
age: "Age",
created_at: "Registration Date",
order_count: "Total Orders",
total_spent: "Lifetime Value",
customer_tier: "Tier",
years_active: "Years Active",
}), []);
const columnWidths = useMemo(() => [
{ wch: 12 }, // ID
{ wch: 25 }, // Name
{ wch: 30 }, // Email
{ wch: 18 }, // Phone
{ wch: 8 }, // Age
{ wch: 22 }, // Created
{ wch: 14 }, // Orders
{ wch: 16 }, // Spent
{ wch: 12 }, // Tier
{ wch: 14 }, // Years
], []);
return {
headers,
columnMapping,
columnWidths,
transformFunction: transformData,
entityName: "customers",
};
}Next Steps
- Subrows - Export with hierarchical data
- Row Selection - Export selected rows
- Server Implementation - Fetch data for export
How is this guide?