Skip to content

HiExport Component

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 Performance

Multiple 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:

Basic HiExport Usage
import React from 'react'
import { HiExport } from '@/components/HiExport'
import { HiTable } from '@/components/HiTable'
import { Button } from '@/components/ui/button'
// Sample data
const 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 transformations
const 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:

HiTable Integration
import React from 'react'
import { HiTable } from '@/components/HiTable'
import { HiExport } from '@/components/HiExport'
import type { ColumnDef } from '@tanstack/react-table'
interface Product {
id: string
name: string
category: string
price: number
stock: number
status: '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 formatting
const 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>
)}
/>
)
}
Advanced Export Configuration
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)}
/>
)
}
Custom Data Transformations
// Define complex column transformations
const 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
<HiExport
data={orders}
columns={advancedExportColumns}
filename="orders-detailed"
format="xlsx"
options={{
currency: 'EUR',
locale: 'de-DE',
dateFormat: 'dd.MM.yyyy',
includeComputedColumns: true
}}
// Sheet configuration for Excel
sheetConfig={{
name: 'Orders Report',
freezeFirstRow: true,
autoFilter: true,
columnStyles: {
total: { numberFormat: '€#,##0.00' },
orderDate: { numberFormat: 'dd/mm/yyyy' }
}
}}
/>

Performance Optimization for Large Datasets

Section titled “Performance Optimization for Large Datasets”
Performance Optimization
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.js
self.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
})
}
}
Export Templates
// Define reusable export templates
const 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 component
export 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>
)
}
Error Handling and Validation
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}%`)
}
}}
/>
)
}
PropTypeDescription
dataT[]Array of data objects to export
columnsExportColumn[]Column definitions with transformations
filenamestringBase filename (without extension)
format'csv' | 'xlsx' | 'json'Export format
tableTable<T>TanStack Table instance for filtered/selected export
exportType'all' | 'filtered' | 'selected' | 'page'Data subset to export
buttonTextstringExport button text
triggerReactNodeCustom trigger element
optionsExportOptionsAdvanced export configuration
onError(error, context) => voidError handler
onSuccess(result) => voidSuccess callback
Column Interface
interface ExportColumn {
key: string // Data property key
header: string // Column header text
accessor?: (row: T, options: ExportOptions) => any // Data transformation function
width?: number // Column width (Excel)
align?: 'left' | 'center' | 'right' // Text alignment
format?: string // Number/date format
computed?: boolean // Indicates computed field
// Excel-specific options
style?: {
font?: { bold?: boolean, color?: string }
fill?: { color?: string }
border?: { style?: string, color?: string }
numberFormat?: string
}
}
Export Options Interface
interface ExportOptions {
// Format-specific options
csv?: {
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 options
dateFormat?: string // Date format pattern
currency?: string // Currency code
locale?: string // Locale for formatting
includeMetadata?: boolean // Include export metadata
compression?: boolean // Compress output file
// Performance options
chunkSize?: number // Processing chunk size
useWebWorker?: boolean // Use Web Worker for processing
maxRows?: number // Maximum rows limit
timeout?: number // Export timeout (ms)
}
Utility Functions
// Built-in utility functions available for column transformations
// Currency formatting
const formatCurrency = (value: number, currency = 'USD', locale = 'en-US') => {
return new Intl.NumberFormat(locale, {
style: 'currency',
currency
}).format(value)
}
// Percentage formatting
const formatPercentage = (value: number, decimals = 2) => {
return `${(value * 100).toFixed(decimals)}%`
}
// Date formatting
const formatDate = (date: Date | string, format = 'yyyy-MM-dd') => {
return format(new Date(date), format)
}
// Text transformations
const capitalizeWords = (text: string) => {
return text.replace(/\w\S*/g, (txt) =>
txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase()
)
}
// Array to string
const arrayToString = (array: any[], separator = ', ') => {
return Array.isArray(array) ? array.join(separator) : String(array)
}
// Usage in column definitions
const 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! 📊💾