demo D280
Bring rows in from a CSV in React
Paste a block or drop a file, each column typed and mapped onto your fields, shown as a preview so nothing lands until you confirm; a spreadsheet block copied from Excel pastes the same way
grid.import.preview() · apply()
This grid brings rows in from a pasted block or a dropped CSV file, typing each column and mapping it onto your fields, shown as a preview so nothing lands until you confirm. It turns a spreadsheet export into grid rows without a separate import tool, and a block copied from Excel pastes the same way.
This is the React version. The grid mounts through the createLatticeGrid adapter, which takes its configuration as ordinary props and hands back the live grid through a ref. The grid below is the same one every other tab runs.
The configuration
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@toclocoinc/lattice-grid@1.71.0/lattice-grid.min.css">
<div id="app"></div>
<script type="module">
import React from 'https://esm.sh/react@18';
import { createRoot } from 'https://esm.sh/react-dom@18/client';
import { createGrid } from 'https://cdn.jsdelivr.net/npm/@toclocoinc/lattice-grid@1.71.0/lattice-grid.esm.min.js';
import createLatticeGrid from 'https://cdn.jsdelivr.net/npm/@toclocoinc/lattice-grid@1.71.0/modules/react.esm.min.js';
const LatticeGrid = createLatticeGrid({ React, createGrid });
const columns = [
{ field: 'sku', title: 'SKU', layout: { width: 110, pin: 'start' } },
{ field: 'name', title: 'Product', layout: { flex: 1, min: 160 } },
{ field: 'category', title: 'Category', filter: { type: 'set' } },
{ field: 'price', title: 'Price', type: 'number', format: { style: 'currency', currency: 'GBP' }, total: 'sum' },
{ field: 'stock', title: 'In stock', type: 'number', total: 'sum' },
];
const rows = [/* the rows already in the grid: sku, name, category, price, stock */];
const CSV = `sku,name,category,price,stock
B-201,Floor lamp,Lighting,72,24
C-300,Bookshelf,Furniture,180,9`;
function App() {
const [grid, setGrid] = React.useState(null);
const [csv, setCsv] = React.useState(CSV);
const [pending, setPending] = React.useState(null);
const [note, setNote] = React.useState('');
// preview() parses the text, infers each column's type and maps it onto
// the grid's own fields, and reports the row count and any warnings, all
// without changing the grid. A spreadsheet block copied from Excel reads
// the same way.
const preview = () => {
const result = grid.import.preview(csv);
setPending(result);
setNote('Ready to add ' + result.rowCount + ' rows, ' + (result.warnings?.length ?? 0) + ' warnings.');
};
// Nothing lands until apply(), so a ragged or mismatched file is caught
// first. mode: 'append' adds the rows; mode: 'replace' would swap the set.
const confirm = () => {
grid.import.apply(pending, { mode: 'append' });
setPending(null);
};
return (
<>
<textarea rows={5} style={{ width: '100%', font: '12px ui-monospace, monospace' }}
value={csv} onChange={(e) => setCsv(e.target.value)} />
<div style={{ margin: '8px 0' }}>
<button onClick={preview} disabled={!grid}>Preview</button>{' '}
<button onClick={confirm} disabled={!pending || pending.rowCount === 0}>Confirm and add</button>{' '}
<span>{note}</span>
</div>
{/* import: true turns on the DOM affordances too: a drop target on the
grid, paste, and a cell-menu item, all running the same
preview-then-confirm pipeline as the buttons above. The
grid.import API is present either way. */}
<LatticeGrid rowKey="id" import columns={columns} rows={rows} onGridReady={setGrid} style={{ height: '460px' }} />
</>
);
}
createRoot(document.getElementById('app')).render(<App />);
</script>