Export & Clipboard
Export Excel
Implement Excel export in LyteNyte Grid using third-party libraries like ExcelJS.
LyteNyte Grid does not include built-in Excel export to keep the bundle size small. Instead, use established open-source libraries to generate Excel files. This approach avoids adding large dependencies to the grid.
This guide shows how to use ExcelJS to create downloadable Excel files from your grid data.
Excel Export
"use client";import { Grid, useClientRowDataSource } from "@1771technologies/lytenyte-pro";import "@1771technologies/lytenyte-pro/grid.css";import type { Column, ExportDataRectResult } from "@1771technologies/lytenyte-pro/types";import { bankDataSmall } from "@1771technologies/sample-data/bank-data-smaller";import type { Worksheet } from "exceljs";import { useId } from "react";type BankData = (typeof bankDataSmall)[number];const columns: Column<BankData>[] = [{ id: "age", type: "number" },{ id: "job" },{ id: "balance", type: "number" },{ id: "education" },{ id: "marital" },{ id: "default" },{ id: "housing" },{ id: "loan" },{ id: "contact" },{ id: "day", type: "number" },{ id: "month" },{ id: "duration" },{ id: "campaign" },{ id: "pdays" },{ id: "previous" },{ id: "poutcome" },{ id: "y" },];export default function ExcelExport() {const ds = useClientRowDataSource({data: bankDataSmall,});const grid = Grid.useLyteNyte({gridId: useId(),rowDataSource: ds,columns,});const view = grid.view.useValue();return (<div style={{ display: "flex", flexDirection: "column" }}><div className="p-2"><buttonclassName="rounded border border-gray-600 bg-gray-900 px-2 text-white dark:text-black"onClick={async () => {const rect = await grid.api.exportDataRect();downloadBlob(await getExcelFile(rect), "data.xlsx");}}>Download Excel File</button></div><div className="lng-grid" style={{ height: 500 }}><Grid.Root grid={grid}><Grid.Viewport><Grid.Header>{view.header.layout.map((row, i) => {return (<Grid.HeaderRow key={i} headerRowIndex={i}>{row.map((c) => {if (c.kind === "group") return null;return (<Grid.HeaderCellkey={c.id}cell={c}className="flex h-full w-full items-center px-2 capitalize"/>);})}</Grid.HeaderRow>);})}</Grid.Header><Grid.RowsContainer><Grid.RowsCenter>{view.rows.center.map((row) => {if (row.kind === "full-width") return null;return (<Grid.Row row={row} key={row.id}>{row.cells.map((c) => {return (<Grid.Cellkey={c.id}cell={c}className="flex h-full w-full items-center px-2 text-sm"/>);})}</Grid.Row>);})}</Grid.RowsCenter></Grid.RowsContainer></Grid.Viewport></Grid.Root></div></div>);}function downloadBlob(blob: Blob, name: string) {// Convert your blob into a Blob URL (a special url that points to an object in the browser's memory)const blobUrl = URL.createObjectURL(blob);// Create a link elementconst link = document.createElement("a");// Set link's href to point to the Blob URLlink.href = blobUrl;link.download = name;// Append link to the bodydocument.body.appendChild(link);// Dispatch click event on the link// This is necessary as link.click() does not work on the latest firefoxlink.dispatchEvent(new MouseEvent("click", {bubbles: true,cancelable: true,view: window,}),);// Remove link from bodydocument.body.removeChild(link);}async function getExcelFile(d: ExportDataRectResult<BankData>) {const excelJs = await import("exceljs");const workbook = new excelJs.Workbook();workbook.creator = "1771 Technologies";workbook.lastModifiedBy = "1771 Technologies";// Set default optionsconst {sheetName = "Data Export",headerBgColor = "4472C4", // Medium blue without # symbolheaderFgColor = "FFFFFF", // White without # symbolalternateRowColors = true,evenRowBgColor = "F2F2F2", // Light gray without # symboloddRowBgColor = "FFFFFF", // White without # symbol} = {};// Create a new workbook and worksheetworkbook.creator = "ExcelJS Export";workbook.lastModifiedBy = "ExcelJS Export";workbook.created = new Date();workbook.modified = new Date();const worksheet = workbook.addWorksheet(sheetName);// Define columnsworksheet.columns = d.columns.map((column, index) => ({header: d.headers[index] || column.name,key: index.toString(),width: Math.max(column.id!.length + 2, 12), // Dynamic width based on header name lengthstyle: {numFmt: column.type === "number" ? "#,##0.00" : "@", // Format numbers with 2 decimal places},}));// Add the datad.data.forEach((row) => {const rowData: Record<string, unknown> = {};row.forEach((cell, cellIndex) => {rowData[cellIndex.toString()] = cell;});worksheet.addRow(rowData);});// Style the header rowconst headerRow = worksheet.getRow(1);headerRow.height = 22;headerRow.font = {name: "Calibri",size: 11,bold: true,color: { argb: headerFgColor },};headerRow.eachCell((cell) => {cell.fill = {type: "pattern",pattern: "solid",fgColor: { argb: headerBgColor },};cell.border = {top: { style: "thin" },left: { style: "thin" },bottom: { style: "thin" },right: { style: "thin" },};cell.alignment = {vertical: "middle",horizontal: "center",};});// Apply alternate row colors for data rowsif (alternateRowColors) {for (let i = 2; i <= worksheet.rowCount; i++) {const rowColor = i % 2 === 0 ? evenRowBgColor : oddRowBgColor;const row = worksheet.getRow(i);row.eachCell({ includeEmpty: true }, (cell) => {cell.fill = {type: "pattern",pattern: "solid",fgColor: { argb: rowColor },};// Style borderscell.border = {top: { style: "thin", color: { argb: "D3D3D3" } },left: { style: "thin", color: { argb: "D3D3D3" } },bottom: { style: "thin", color: { argb: "D3D3D3" } },right: { style: "thin", color: { argb: "D3D3D3" } },};// Align cell contentcell.alignment = {vertical: "middle",horizontal: cell.value !== null && typeof cell.value === "number" ? "right" : "left",};});}}// Apply auto-filters to the header rowworksheet.autoFilter = {from: { row: 1, column: 1 },to: { row: 1, column: d.headers.length },};// Freeze the top rowworksheet.views = [{ state: "frozen", xSplit: 0, ySplit: 1, activeCell: "A2" }];d.columns.forEach((_, index) => {const columnWidth = estimateColumnWidth(worksheet, index);worksheet.getColumn(index + 1).width = columnWidth;});// Write to a bufferconst buffer = await workbook.xlsx.writeBuffer();// Create a blob from the bufferconst blob = new Blob([buffer], {type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",});return blob;}function estimateColumnWidth(worksheet: Worksheet, columnIndex: number) {let maxWidth = 10; // Default minimum width// Check header width (adding extra space for padding)const headerCell = worksheet.getCell(1, columnIndex + 1);if (headerCell && headerCell.value) {const headerLength = String(headerCell.value).length;maxWidth = Math.max(maxWidth, headerLength + 4); // Add padding}// Check data cell widthsworksheet.eachRow({ includeEmpty: false }, function (row, rowNumber) {if (rowNumber > 1) {// Skip headerconst cell = row.getCell(columnIndex + 1);if (cell && cell.value !== null && cell.value !== undefined) {let cellLength = String(cell.value).length;// Add extra width for numbers with formattingif (typeof cell.value === "number") {cellLength += 3; // Add extra space for formatting}maxWidth = Math.max(maxWidth, cellLength + 2); // Add padding}}});// Cap maximum width to prevent extremely wide columnsreturn Math.min(maxWidth, 50);}
How It Works
Use the exportDataRect API method to retrieve the grid's data for export. Pass this data into your
ExcelJS logic to populate and style the spreadsheet. For details on exportDataRect, see the
Export Any Data guide.