Spreadsheet recipe
Data operations
Exercise CSV/XLSX transfer, contextual row actions, soft delete, and undo.
CSVXLSXRow actions
Interactive, production component
tsx
import { useState } from "react";
import { DataTable } from "../../Datatable";
import type { ColumnSetting } from "../../Datatable";
import { products as initialProducts, type ProductRow } from "./exampleData";
import type { ExampleProps } from "./types";
type OperationsRow = ProductRow & { deleted?: boolean };
const columns: ColumnSetting<OperationsRow>[] = [
{ id: "id", title: "ID", width: 80, align: "right", headerAlign: "center" },
{ id: "sku", title: "SKU", width: 110, editor: "text" },
{ id: "product", title: "Product", width: 200, editor: "text" },
{ id: "brand", title: "Brand", width: 100, editor: "text" },
{ id: "category", title: "Category", width: 120, editor: "text" },
{ id: "subcategory", title: "Line", width: 100, editor: "text" },
{ id: "region", title: "Region", width: 90, editor: "text" },
{ id: "warehouse", title: "Warehouse", width: 110, editor: "text" },
{ id: "stock", title: "Stock", width: 90, align: "right", editor: "number" },
{ id: "reserved", title: "Reserved", width: 100, align: "right", editor: "number" },
{ id: "price", title: "Price", width: 100, align: "right", editor: "number" },
{ id: "cost", title: "Cost", width: 100, align: "right", editor: "number" },
{ id: "margin", title: "Margin %", width: 100, align: "right", editor: "number" },
{ id: "rating", title: "Rating", width: 90, align: "right", editor: "number" },
{ id: "status", title: "Status", width: 110, editor: "text" },
{ id: "owner", title: "Owner", width: 130, editor: "text" },
{ id: "countryCode", title: "Country", width: 90, editor: "text" },
{ id: "reviews", title: "Reviews", width: 100, align: "right", editor: "number" },
{ id: "reorderAt", title: "Reorder", width: 90, align: "right", editor: "number" },
{ id: "updatedAt", title: "Updated", width: 110, editor: "text" },
];
export default function OperationsExample({ theme }: ExampleProps) {
const [rows, setRows] = useState<OperationsRow[]>(() => [...initialProducts]);
return (
<DataTable
theme={theme}
title="Catalog operations"
dataSource={rows}
onChange={setRows}
columnSettings={columns}
maxHeight={480}
enablePagination
enableEditing
enableRowSelection
enableMultiRowSelection
enableRowIndex
enableDownload
enableUpload
defaultFileName="product-catalog"
enableRowActions
softDeleteKey="deleted"
undoLimit={20}
redoLimit={20}
createEmptyRow={(index) => ({
id: Date.now() + index,
sku: `VB-NEW-${index}`,
product: "Untitled product",
brand: "Vibe",
category: "Uncategorized",
subcategory: "New",
region: "NA",
countryCode: "us",
warehouse: "SFO-1",
stock: 0,
reserved: 0,
reorderAt: 10,
price: 0,
cost: 0,
margin: 0,
rating: 0,
reviews: 0,
status: "Draft" as const,
owner: "Unassigned",
featured: false,
updatedAt: "2026-07-16",
thumb: `https://picsum.photos/seed/new-${index}/64/64`,
})}
/>
);
}
Related API