Skip to content

Excel Import/Export

The ExcelPlugin provides Excel file import and export via SheetJS (Apache-2.0). SheetJS is lazy-loaded from CDN on first use — no bundle size impact until you actually import or export.

Live Demo
Upload an .xlsx file or export the current table to Excel.
Ready
View source code
ExcelDemo.tsx
import { useRef, useEffect, useState } from 'react';
import { WitTable } from '@witqq/spreadsheet-react';
import type { WitTableRef } from '@witqq/spreadsheet-react';
import { ExcelPlugin } from '@witqq/spreadsheet-plugins';
import { DemoWrapper } from './DemoWrapper';
import { generateEmployees, employeeColumns } from './generate-data';
import { useSiteTheme } from './useSiteTheme';
const data = generateEmployees(15);
export function ExcelDemo() {
const { witTheme } = useSiteTheme();
const tableRef = useRef<WitTableRef>(null);
const pluginRef = useRef<ExcelPlugin | null>(null);
const fileInputRef = useRef<HTMLInputElement>(null);
const [status, setStatus] = useState('Ready');
useEffect(() => {
const engine = tableRef.current?.getInstance();
if (!engine) return;
const plugin = new ExcelPlugin();
engine.installPlugin(plugin);
pluginRef.current = plugin;
}, []);
const handleExport = async () => {
if (!pluginRef.current) return;
try {
setStatus('Exporting...');
const buffer = await pluginRef.current.exportExcel({ sheetName: 'Employees' });
const blob = new Blob([buffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'witqq-export.xlsx';
a.click();
URL.revokeObjectURL(url);
setStatus('Exported to witqq-export.xlsx');
} catch (e) {
setStatus(`Export error: ${e instanceof Error ? e.message : String(e)}`);
}
};
const handleImport = async (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (!file || !pluginRef.current) return;
try {
setStatus(`Importing ${file.name}...`);
const buffer = await file.arrayBuffer();
const result = await pluginRef.current.importExcel(buffer);
setStatus(`Imported ${result.rowCount} rows from "${result.sheetName}"`);
} catch (err) {
setStatus(`Import error: ${err instanceof Error ? err.message : String(err)}`);
}
e.target.value = '';
};
return (
<DemoWrapper title="Live Demo" description="Upload an .xlsx file or export the current table to Excel." height={440}>
<div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
<div style={{ padding: '0.5rem 0.75rem', borderBottom: '1px solid #e2e8f0', flexShrink: 0, display: 'flex', gap: '0.5rem', alignItems: 'center' }}>
<input
ref={fileInputRef}
type="file"
accept=".xlsx"
onChange={handleImport}
style={{ display: 'none' }}
/>
<button onClick={() => fileInputRef.current?.click()} style={{ padding: '4px 12px', cursor: 'pointer' }}>📥 Import Excel</button>
<button onClick={handleExport} style={{ padding: '4px 12px', cursor: 'pointer' }}>📤 Export Excel</button>
<span style={{ fontSize: '0.8rem', color: '#64748b' }}>{status}</span>
</div>
<div style={{ flex: 1 }}>
<WitTable
theme={witTheme}
ref={tableRef}
columns={employeeColumns}
data={data}
showRowNumbers
editable
style={{ width: '100%', height: '100%' }}
/>
</div>
</div>
</DemoWrapper>
);
}
import { ExcelPlugin } from '@witqq/spreadsheet-plugins';
const excelPlugin = new ExcelPlugin();
engine.installPlugin(excelPlugin);
importExcel(buffer: ArrayBuffer, sheetIndex?: number): Promise<ExcelImportResult>

Reads an .xlsx file buffer and returns structured data ready to apply to the table.

interface ExcelImportResult {
columns: ColumnDef[]; // Auto-detected column definitions
rowCount: number; // Number of data rows
sheetName: string; // Name of the imported sheet
}

Features:

  • Auto-detects column types from cell data (string, number, date, boolean)
  • Preserves column widths from the Excel file
  • Handles merged regions
import { ExcelPlugin } from '@witqq/spreadsheet-plugins';
import { WitTable, WitTableRef } from '@witqq/spreadsheet-react';
function App() {
const ref = useRef<WitTableRef>(null);
const excelRef = useRef<ExcelPlugin>();
const [columns, setColumns] = useState<ColumnDef[]>([]);
const [data, setData] = useState<Record<string, unknown>[]>([]);
useEffect(() => {
const plugin = new ExcelPlugin();
excelRef.current = plugin;
ref.current?.installPlugin(plugin);
}, []);
const handleImport = async (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (!file || !excelRef.current) return;
const buffer = await file.arrayBuffer();
const result = await excelRef.current.importExcel(buffer);
setColumns(result.columns);
// Data is applied to the engine internally;
// update React state to match
};
return (
<div>
<input type="file" accept=".xlsx,.xls" onChange={handleImport} />
<WitTable ref={ref} columns={columns} data={data} />
</div>
);
}
exportExcel(options?: ExcelExportOptions): Promise<ArrayBuffer>

Exports the current table data as an .xlsx file buffer.

interface ExcelExportOptions {
sheetName?: string; // Sheet name (default: 'Sheet1')
includeHeaders?: boolean; // Include column headers (default: true)
maxRows?: number; // Limit exported rows
}
const handleExport = async () => {
if (!excelRef.current) return;
const buffer = await excelRef.current.exportExcel({
sheetName: 'Sales Data',
includeHeaders: true,
});
// Trigger browser download
const blob = new Blob([buffer], {
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
});
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'export.xlsx';
a.click();
URL.revokeObjectURL(url);
};
return <button onClick={handleExport}>Export to Excel</button>;

SheetJS (v0.20.3) is loaded from CDN on first importExcel or exportExcel call. This keeps the core bundle small — the ~300KB SheetJS library is only fetched when needed.

If you need to pre-load SheetJS (e.g. to avoid latency on first use), the plugin handles caching automatically after the first load.