react data grid · excel export
React Grid: Excel Export
grid.export.excel() writes a real, styled workbook in the browser: frozen panes, a named sheet, banded row fills. Wire it to the built-in toolbar action, your own button, or both, reached through the same ref every imperative call in React goes through.
Also in: Angular
Install and import
npm install @toclocoinc/lattice-grid
# free on localhost; a production domain needs a licence key (see /pricing/)
The files
lattice.ts
// lattice.ts
import React from 'react';
import { createGrid } from '@toclocoinc/lattice-grid';
import '@toclocoinc/lattice-grid/css';
import { createLatticeGrid } from '@toclocoinc/lattice-grid/modules/react';
export const LatticeGrid = createLatticeGrid({ React, createGrid });
SupplierCharges.tsx
// SupplierCharges.tsx
import React from 'react';
import { createRoot } from 'react-dom/client';
import { LatticeGrid } from './lattice';
const columns = [
{ field: 'ref', title: 'Invoice', layout: { pin: 'start', width: 140 } },
{ field: 'supplier', title: 'Supplier', layout: { flex: 1, min: 200 }, filter: { type: 'set' } },
{ field: 'region', title: 'Region', filter: { type: 'set' } },
{ field: 'category', title: 'Category', filter: { type: 'set' } },
{ field: 'quantity', title: 'Qty', type: 'number', layout: { width: 110 } },
{ field: 'amount', title: 'Amount', type: 'number', layout: { width: 150 },
format: { style: 'currency', currency: 'GBP', decimals: 2 }, total: 'sum', filter: { type: 'number' } },
{ field: 'note', title: 'Note', layout: { width: 280 } },
];
// The workbook is written in the browser with no dependency: a zip
// container, the sheet, the shared strings and the styles, all assembled by
// the grid. Nothing is uploaded and nothing is fetched.
const toolPanel = {
side: 'left',
panels: ['columns', 'filters', 'quick'],
exportName: 'supplier-charges',
actions: [
'undo', 'redo', 'restore', 'maximise', '-',
'excel',
{
name: 'excel-named',
title: 'Download .xlsx, named sheet with a frozen header',
icon: 'spreadsheet',
run: ({ grid }: any) => grid.export.excel({
download: true,
fileName: 'supplier-charges-q3',
sheetName: 'Charges',
freezePanes: true,
variantFills: true,
}),
},
'clipboard',
],
};
const rows = [/* supplier charge records, one per invoice line */];
function SupplierCharges() {
const gridRef = React.useRef<{ grid: any } | null>(null);
// The same writer, reached imperatively through the ref: a named sheet
// with a frozen header, triggered from your own button.
const download = () => gridRef.current?.grid.export.excel({
download: true,
fileName: 'supplier-charges-q3',
sheetName: 'Charges',
freezePanes: true,
variantFills: true,
});
return (
<>
<button onClick={download}>Download .xlsx</button>
<LatticeGrid
ref={gridRef}
rowKey="id"
selection="multiple"
toolPanel={toolPanel}
columns={columns}
rows={rows}
style={{ height: '460px', marginTop: '8px' }}
/>
</>
);
}
createRoot(document.getElementById('supplier-charges')!).render(<SupplierCharges />);
See it running
Working in React
Two routes to the same writer. The toolbar's built-in 'excel' action
downloads with the grid's defaults; a named custom action or your own button both call
grid.export.excel(options) directly, reached through ref.current.grid
after mount. Neither route needs a server: the workbook is assembled entirely in the tab.
Only what the reader can see. Export follows the current filter and sort by default, so a filtered view exports the filtered rows, not the full dataset behind it.
StrictMode is handled the same way editing is: the development double-mount destroys the first grid instance in its effect cleanup, so a second click on Download always reaches the grid actually on screen.
Related
Read the docs React data grid overview Free on localhost. See pricing.