Install and render the first grid
View as MarkdownBuild a local typed grid before adding a remote source or application-specific workflow.
Agent approach
Section titled “Agent approach”In a React application, install @sapporta/grid and build a small local task grid with typed title and status columns, stable row identity, keyboard navigation, and the standard copy menu. Use only public package exports. Run the app build and report the changed files and checks.Review the agent’s work
Section titled “Review the agent’s work”- The package and CSS import use public export paths.
- The schema has one stable root level and every source row has a stable
rowKey. - The runtime is disposed with the React lifecycle.
- The copy menu returns stored values and labels in deterministic column order.
Code approach
Section titled “Code approach”Install the standalone package in a React app:
pnpm add @sapporta/gridImport the Grid CSS once, usually next to the rest of your app styles:
import "@sapporta/grid/index.css";Then create a schema, rows, a runtime, and a React surface:
import { GridCopyContextMenu, GridLevel, GridRuntimeProvider, createGridRuntime, inMemoryGridDataSource, useGridRuntimeEffect, type GridSchema, type TreeNode,} from "@sapporta/grid";import { select, text } from "@sapporta/grid/column-preset";
const schema: GridSchema = { rootLevel: "tasks", levels: { tasks: { name: "tasks", rowHeaderColumn: "none", childLevels: [], columns: [ text({ id: "title", name: "Task", edit: "default", width: "fill" }), select({ id: "status", name: "Status", edit: "default", options: [ { value: "todo", label: "To do" }, { value: "doing", label: "Doing" }, { value: "done", label: "Done" }, ], }), ], options: {}, }, },};
const tree: TreeNode[] = [ { rowKey: "1", levelName: "tasks", columns: { title: "Review import workflow", status: "doing" }, }, { rowKey: "2", levelName: "tasks", columns: { title: "Ship keyboard polish", status: "todo" }, },];
export function TaskGrid() { const runtime = useGridRuntimeEffect( () => createGridRuntime({ schema, dataSource: inMemoryGridDataSource({ schema, tree, levels: { tasks: { sortMode: "client", filterMode: "none", paginationMode: "none", }, }, }), }), [], );
if (!runtime) return null;
return ( <GridRuntimeProvider runtime={runtime}> <GridCopyContextMenu> <GridLevel path={runtime.root.path} /> </GridCopyContextMenu> </GridRuntimeProvider> );}GridCopyContextMenu gives the standalone grid the standard right-click copy
menu. Right-click the active cell or a selected range, choose Copy to write
CSV values, or choose Copy with headers to include stable column ids. The
status select column contributes both the stored value and label, so copying
it with headers produces status,status_label.
That first grid is intentionally local. It proves the visible surface, column model, row identity, and keyboard behavior before you connect a backend.
When the grid should read or write server data, keep the schema and React surface. Replace the in-memory data source with your own source or save handlers.
Observe and verify
Section titled “Observe and verify”The build passes. Arrow keys move the active cell, editing updates the local row, and Copy with headers writes the expected task columns.
What you built
Section titled “What you built”The grid owns its schema, runtime, local data source, interactions, and React surface. Continue by choosing the correct layer for the next requirement. Next: Choose a grid layer