Multiple Formats
CSV and Excel (.xlsx) export with customizable formatting options
Export table data effortlessly with HiExport - a comprehensive data export solution supporting multiple formats, custom transformations, and performance optimization for large datasets.
CSV Export Excel Support High PerformanceMultiple Formats
CSV and Excel (.xlsx) export with customizable formatting options
Data Transformation
Custom data mapping, formatting, and column selection
Export Options
Export all data, selected rows, current page, or filtered results
Performance Optimized
Streaming export for large datasets with progress indicators
User Experience
Intuitive UI with export previews and customization options
Integration Ready
Seamless integration with HiTable and custom data sources
Basic export functionality with HiTable integration:
import React from 'react'import { HiExport } from '@/components/HiExport'import { HiTable } from '@/components/HiTable'import { Button } from '@/components/ui/button'
// Sample dataconst users = [{ id: 1, name: 'John Doe', role: 'Admin', createdAt: new Date('2024-01-15'), salary: 75000},{ id: 2, name: 'Jane Smith', role: 'User', createdAt: new Date('2024-02-10'), salary: 65000}// ... more users]
// Define export columns with transformationsconst exportColumns = [{ key: 'id', header: 'User ID'},{ key: 'name', header: 'Full Name'},{ key: 'email', header: 'Email Address'},{ key: 'role', header: 'User Role'},{ key: 'createdAt', header: 'Registration Date', accessor: (row) => row.createdAt.toLocaleDateString()},{ key: 'salary', header: 'Annual Salary', accessor: (row) => new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(row.salary)}]
export default function UserExportExample() {return ( <div className="space-y-4"> {/* Basic Export Button */} <HiExport data={users} columns={exportColumns} filename="users-export" buttonText="Export Users" format="csv" />
{/* Export with custom trigger */} <HiExport data={users} columns={exportColumns} filename="users-detailed" format="xlsx" trigger={ <Button variant="outline" className="w-full"> 📊 Export to Excel </Button> } /> </div>)}
Seamlessly export table data with built-in filtering and selection:
import React from 'react'import { HiTable } from '@/components/HiTable'import { HiExport } from '@/components/HiExport'import type { ColumnDef } from '@tanstack/react-table'
interface Product {id: stringname: stringcategory: stringprice: numberstock: numberstatus: 'active' | 'inactive'}
export default function ProductTableWithExport() {const [products, setProducts] = React.useState<Product[]>([])
const columns: ColumnDef<Product>[] = [ { accessorKey: 'id', header: 'ID' }, { accessorKey: 'name', header: 'Product Name' }, { accessorKey: 'category', header: 'Category' }, { accessorKey: 'price', header: 'Price', cell: ({ row }) => `$${row.getValue('price')}` }, { accessorKey: 'stock', header: 'Stock' }, { accessorKey: 'status', header: 'Status' }]
// Export columns with custom formattingconst exportColumns = [ { key: 'id', header: 'Product ID' }, { key: 'name', header: 'Product Name' }, { key: 'category', header: 'Category' }, { key: 'price', header: 'Price (USD)', accessor: (row) => `$${row.price.toFixed(2)}` }, { key: 'stock', header: 'Available Stock', accessor: (row) => `${row.stock} units` }, { key: 'status', header: 'Status', accessor: (row) => row.status.charAt(0).toUpperCase() + row.status.slice(1) }]
return ( <HiTable data={products} columns={columns} config={{ pagination: { enabled: true, pageSize: 20 }, sorting: { enabled: true }, filtering: { enabled: true, searchable: true }, rowSelection: { enabled: true, mode: 'multiple' } }} toolbarActions={(table) => ( <div className="flex items-center space-x-2"> {/* Export all products */} <HiExport data={products} columns={exportColumns} filename="all-products" buttonText="Export All" size="sm" variant="outline" />
{/* Export filtered data */} <HiExport table={table} originalData={products} columns={exportColumns} filename="filtered-products" buttonText="Export Filtered" size="sm" variant="outline" exportType="filtered" />
{/* Export selected rows */} <HiExport table={table} originalData={products} columns={exportColumns} filename="selected-products" buttonText="Export Selected" size="sm" variant="outline" exportType="selected" disabled={table.getSelectedRowModel().rows.length === 0} /> </div> )} />)}
import React, { useState } from 'react'import { HiExportExtended } from '@/components/HiExport'
export default function AdvancedExportExample() {const [exportConfig, setExportConfig] = useState({ format: 'csv', includeHeaders: true, dateFormat: 'YYYY-MM-DD', numberFormat: 'US'})
const handleExportConfigChange = (config) => { setExportConfig(config)}
return ( <HiExportExtended data={salesData} columns={salesColumns} filename="sales-report"
// Export options options={{ showDialog: true, formats: ['csv', 'xlsx', 'json'], exportTypes: ['all', 'filtered', 'selected', 'page'], customization: { dateFormats: [ { label: 'MM/DD/YYYY', value: 'MM/DD/YYYY' }, { label: 'DD/MM/YYYY', value: 'DD/MM/YYYY' }, { label: 'YYYY-MM-DD', value: 'YYYY-MM-DD' } ], numberFormats: [ { label: 'US (1,234.56)', value: 'US' }, { label: 'EU (1.234,56)', value: 'EU' } ] } }}
// Advanced configuration config={{ chunkSize: 1000, // Process in chunks for performance includeMetadata: true, compression: true, preview: { enabled: true, maxRows: 5 } }}
// Custom transformations transformers={{ currency: (value, options) => { return new Intl.NumberFormat(options.locale, { style: 'currency', currency: options.currency || 'USD' }).format(value) }, percentage: (value) => `${(value * 100).toFixed(2)}%`, capitalize: (value) => value.charAt(0).toUpperCase() + value.slice(1) }}
onConfigChange={handleExportConfigChange} onExportStart={(config) => console.log('Export started:', config)} onExportComplete={(result) => console.log('Export completed:', result)} />)}
// Define complex column transformationsconst advancedExportColumns = [{ key: 'id', header: 'Order ID', width: 120},{ key: 'customer', header: 'Customer Information', accessor: (row) => `${row.customer.name} (${row.customer.email})`, width: 300},{ key: 'orderDate', header: 'Order Date', accessor: (row, options) => { const date = new Date(row.orderDate) return options.dateFormat === 'relative' ? formatDistanceToNow(date, { addSuffix: true }) : format(date, options.dateFormat || 'yyyy-MM-dd') }, width: 150},{ key: 'items', header: 'Items', accessor: (row) => row.items.map(item => `${item.name} (x${item.quantity})` ).join(', '), width: 400},{ key: 'total', header: 'Total Amount', accessor: (row, options) => { const currency = options.currency || 'USD' const locale = options.locale || 'en-US'
return new Intl.NumberFormat(locale, { style: 'currency', currency: currency }).format(row.total) }, width: 120, align: 'right'},{ key: 'status', header: 'Status', accessor: (row) => { const statusLabels = { pending: 'Pending Payment', processing: 'Processing', shipped: 'Shipped', delivered: 'Delivered', cancelled: 'Cancelled' } return statusLabels[row.status] || row.status }, width: 150},// Computed columns{ key: 'profitMargin', header: 'Profit Margin', accessor: (row) => { const profit = row.total - row.cost const margin = (profit / row.total) * 100 return `${margin.toFixed(2)}%` }, width: 120, computed: true // Indicates this is a computed field}]
// Usage with custom options<HiExportdata={orders}columns={advancedExportColumns}filename="orders-detailed"format="xlsx"options={{ currency: 'EUR', locale: 'de-DE', dateFormat: 'dd.MM.yyyy', includeComputedColumns: true}}// Sheet configuration for ExcelsheetConfig={{ name: 'Orders Report', freezeFirstRow: true, autoFilter: true, columnStyles: { total: { numberFormat: '€#,##0.00' }, orderDate: { numberFormat: 'dd/mm/yyyy' } }}}/>
import React, { useState } from 'react'import { HiExport } from '@/components/HiExport'import { Progress } from '@/components/ui/progress'
export default function LargeDataExport() {const [exportProgress, setExportProgress] = useState(0)const [isExporting, setIsExporting] = useState(false)
const handleLargeDataExport = async () => { setIsExporting(true) setExportProgress(0)
try { // For very large datasets (10k+ rows), use streaming const result = await HiExport.streamExport({ dataSource: async (offset, limit) => { // Fetch data in chunks from your API const response = await fetch(`/api/data?offset=${offset}&limit=${limit}`) return response.json() }, totalCount: 50000, // Total number of records chunkSize: 1000, // Process 1000 records at a time columns: exportColumns, filename: 'large-dataset', format: 'xlsx',
// Progress callback onProgress: (progress) => { setExportProgress(progress) },
// Memory optimization optimization: { useWebWorker: true, // Use Web Worker for processing compression: true, // Compress output streamToDisk: true // Stream directly to file (where supported) } })
console.log('Export completed:', result) } catch (error) { console.error('Export failed:', error) } finally { setIsExporting(false) setExportProgress(0) }}
return ( <div className="space-y-4"> <HiExport // For smaller datasets, use regular export data={smallDataset} columns={exportColumns} filename="regular-export" buttonText="Export Small Dataset" />
{/* Large dataset export with progress */} <div className="space-y-2"> <button onClick={handleLargeDataExport} disabled={isExporting} className="w-full px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700 disabled:opacity-50" > {isExporting ? 'Exporting...' : 'Export Large Dataset (50k records)'} </button>
{isExporting && ( <div className="space-y-2"> <Progress value={exportProgress} className="w-full" /> <p className="text-sm text-muted-foreground text-center"> Exporting... {Math.round(exportProgress)}% </p> </div> )} </div> </div>)}
// Web Worker implementation for background processing// workers/exportWorker.jsself.onmessage = function(e) {const { data, columns, format, options } = e.data
try { // Process data transformation in background const processedData = data.map(row => { const processedRow = {}
columns.forEach(column => { if (column.accessor && typeof column.accessor === 'function') { processedRow[column.key] = column.accessor(row, options) } else { processedRow[column.key] = row[column.key] } })
return processedRow })
// Send processed data back to main thread self.postMessage({ success: true, data: processedData, progress: 100 })
} catch (error) { self.postMessage({ success: false, error: error.message })}}
// Define reusable export templatesconst exportTemplates = {userSummary: { name: 'User Summary', description: 'Basic user information for reports', columns: [ { key: 'id', header: 'ID' }, { key: 'name', header: 'Name' }, { key: 'email', header: 'Email' }, { key: 'role', header: 'Role' }, { key: 'lastLogin', header: 'Last Login', accessor: (row) => row.lastLogin ? format(new Date(row.lastLogin), 'yyyy-MM-dd HH:mm') : 'Never' } ], format: 'csv', options: { includeHeaders: true, dateFormat: 'yyyy-MM-dd' }},
userDetailed: { name: 'User Detailed Report', description: 'Comprehensive user data with activity metrics', columns: [ { key: 'id', header: 'User ID' }, { key: 'name', header: 'Full Name' }, { key: 'email', header: 'Email Address' }, { key: 'role', header: 'User Role' }, { key: 'department', header: 'Department' }, { key: 'createdAt', header: 'Registration Date', accessor: (row) => format(new Date(row.createdAt), 'yyyy-MM-dd') }, { key: 'loginCount', header: 'Total Logins' }, { key: 'lastActivity', header: 'Last Activity', accessor: (row) => row.lastActivity ? formatDistanceToNow(new Date(row.lastActivity), { addSuffix: true }) : 'Never' } ], format: 'xlsx', sheetConfig: { name: 'User Report', freezeFirstRow: true, autoFilter: true }},
financialReport: { name: 'Financial Summary', description: 'Revenue and financial metrics', columns: [ { key: 'period', header: 'Period' }, { key: 'revenue', header: 'Revenue', accessor: (row, opts) => formatCurrency(row.revenue, opts.currency) }, { key: 'expenses', header: 'Expenses', accessor: (row, opts) => formatCurrency(row.expenses, opts.currency) }, { key: 'profit', header: 'Net Profit', accessor: (row, opts) => formatCurrency(row.profit, opts.currency) }, { key: 'profitMargin', header: 'Profit Margin', accessor: (row) => `${((row.profit / row.revenue) * 100).toFixed(2)}%` } ], format: 'xlsx', options: { currency: 'USD' }}}
// Template selector componentexport default function TemplatedExport({ data }) {const [selectedTemplate, setSelectedTemplate] = useState('userSummary')
const template = exportTemplates[selectedTemplate]
return ( <div className="space-y-4"> {/* Template selector */} <div> <label className="block text-sm font-medium mb-2"> Export Template </label> <select value={selectedTemplate} onChange={(e) => setSelectedTemplate(e.target.value)} className="w-full p-2 border rounded" > {Object.entries(exportTemplates).map(([key, template]) => ( <option key={key} value={key}> {template.name} </option> ))} </select> <p className="text-sm text-muted-foreground mt-1"> {template.description} </p> </div>
{/* Export with selected template */} <HiExport data={data} columns={template.columns} filename={selectedTemplate} format={template.format} options={template.options} sheetConfig={template.sheetConfig} buttonText={`Export ${template.name}`} />
{/* Save custom template */} <SaveTemplateDialog onSave={(newTemplate) => { exportTemplates[newTemplate.key] = newTemplate setSelectedTemplate(newTemplate.key) }} /> </div>)}
import React from 'react'import { HiExport } from '@/components/HiExport'import { toast } from 'sonner'
export default function ExportWithErrorHandling() {const handleExportError = (error, context) => { console.error('Export failed:', error, context)
// Show user-friendly error messages switch (error.code) { case 'INVALID_DATA': toast.error('Export failed: Invalid data format') break case 'FILE_SIZE_LIMIT': toast.error('Export failed: File size exceeds limit (100MB)') break case 'NETWORK_ERROR': toast.error('Export failed: Network connection error') break case 'PERMISSION_DENIED': toast.error('Export failed: Insufficient permissions') break default: toast.error(`Export failed: ${error.message}`) }}
const handleExportSuccess = (result) => { toast.success(`Export completed: ${result.filename}`)
// Analytics tracking trackEvent('export_success', { format: result.format, rowCount: result.rowCount, fileSize: result.fileSize })}
return ( <HiExport data={sensitiveData} columns={exportColumns} filename="secure-export"
// Validation rules validation={{ maxRows: 50000, maxFileSize: '100MB', requiredPermissions: ['export_data', 'view_sensitive'],
// Custom validation functions validateRow: (row, index) => { if (!row.id) { return `Row ${index + 1}: Missing ID` } if (!row.email || !isValidEmail(row.email)) { return `Row ${index + 1}: Invalid email format` } return true },
validateColumn: (column, data) => { if (column.key === 'salary' && data.some(row => row.salary < 0)) { return 'Salary column contains negative values' } return true } }}
// Security settings security={{ sanitizeData: true, // Remove potentially harmful content encryptOutput: false, // Encrypt exported file requireConfirmation: true, // Show confirmation dialog auditLog: true // Log export activity }}
// Error handling onError={handleExportError} onSuccess={handleExportSuccess} onValidationError={(errors) => { toast.error(`Validation failed: ${errors.length} issues found`) console.log('Validation errors:', errors) }}
// Progress tracking onProgress={(progress) => { if (progress.phase === 'validation') { toast.loading('Validating data...') } else if (progress.phase === 'processing') { toast.loading(`Processing... ${progress.percentage}%`) } }} />)}
Prop | Type | Description |
---|---|---|
data | T[] | Array of data objects to export |
columns | ExportColumn[] | Column definitions with transformations |
filename | string | Base filename (without extension) |
format | 'csv' | 'xlsx' | 'json' | Export format |
table | Table<T> | TanStack Table instance for filtered/selected export |
exportType | 'all' | 'filtered' | 'selected' | 'page' | Data subset to export |
buttonText | string | Export button text |
trigger | ReactNode | Custom trigger element |
options | ExportOptions | Advanced export configuration |
onError | (error, context) => void | Error handler |
onSuccess | (result) => void | Success callback |
interface ExportColumn {key: string // Data property keyheader: string // Column header textaccessor?: (row: T, options: ExportOptions) => any // Data transformation functionwidth?: number // Column width (Excel)align?: 'left' | 'center' | 'right' // Text alignmentformat?: string // Number/date formatcomputed?: boolean // Indicates computed field
// Excel-specific optionsstyle?: { font?: { bold?: boolean, color?: string } fill?: { color?: string } border?: { style?: string, color?: string } numberFormat?: string}}
interface ExportOptions {// Format-specific optionscsv?: { delimiter?: string // Field delimiter (default: ',') quote?: string // Quote character (default: '"') escape?: string // Escape character header?: boolean // Include header row encoding?: 'utf8' | 'utf16le' // File encoding}
xlsx?: { sheetName?: string // Worksheet name freezeFirstRow?: boolean // Freeze header row autoFilter?: boolean // Enable auto-filter columnStyles?: Record<string, any> // Column-specific styles protection?: { // Sheet protection password?: string selectLockedCells?: boolean selectUnlockedCells?: boolean }}
// General optionsdateFormat?: string // Date format patterncurrency?: string // Currency codelocale?: string // Locale for formattingincludeMetadata?: boolean // Include export metadatacompression?: boolean // Compress output file
// Performance optionschunkSize?: number // Processing chunk sizeuseWebWorker?: boolean // Use Web Worker for processingmaxRows?: number // Maximum rows limittimeout?: number // Export timeout (ms)}
// Built-in utility functions available for column transformations
// Currency formattingconst formatCurrency = (value: number, currency = 'USD', locale = 'en-US') => {return new Intl.NumberFormat(locale, { style: 'currency', currency}).format(value)}
// Percentage formattingconst formatPercentage = (value: number, decimals = 2) => {return `${(value * 100).toFixed(decimals)}%`}
// Date formattingconst formatDate = (date: Date | string, format = 'yyyy-MM-dd') => {return format(new Date(date), format)}
// Text transformationsconst capitalizeWords = (text: string) => {return text.replace(/\w\S*/g, (txt) => txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase())}
// Array to stringconst arrayToString = (array: any[], separator = ', ') => {return Array.isArray(array) ? array.join(separator) : String(array)}
// Usage in column definitionsconst columns: ExportColumn[] = [{ key: 'price', header: 'Price', accessor: (row) => formatCurrency(row.price, 'EUR', 'de-DE')},{ key: 'tags', header: 'Tags', accessor: (row) => arrayToString(row.tags, ' | ')},{ key: 'name', header: 'Name', accessor: (row) => capitalizeWords(row.name)}]
HiExport provides comprehensive data export capabilities with excellent performance and user experience! 📊💾