wcz-layout
Version:
230 lines (176 loc) • 6.08 kB
Markdown
name: data-grid
description: >
MUI X DataGrid Premium with wcz-layout helpers. ChipInputCell for chip
rendering in cells (getLabel for complex objects). EditableColumnHeader
for pencil icon headers. RouterGridActionsCellItem for type-safe row
action navigation. Column definitions with renderCell/renderHeader.
Feed rows from useLiveQuery collection data. Activate when building
data tables or grids.
type: composition
library: wcz-layout
library_version: "7.6.1"
requires:
- tanstack-db-collections
- ui-pages
sources:
- "wcz-layout:src/components/data-grid/ChipInputCell.tsx"
- "wcz-layout:src/components/data-grid/EditableColumnHeader.tsx"
- "wcz-layout:src/components/router/RouterGridActionsCellItem.tsx"
# Data Grid
## Setup
Install `@mui/x-data-grid-premium` (peer dependency). Use `DataGridPremium`, not the community `DataGrid`.
## Core Patterns
### Basic data grid with collection data
```typescript
import { DataGridPremium, type GridColDef } from "@mui/x-data-grid-premium";
import { useLiveQuery } from "@tanstack/react-db";
import { todoCollection } from "~/lib/db/collections/todoCollection";
import type { Todo } from "~/schemas/todo";
const columns: GridColDef<Todo>[] = [
{ field: "name", headerName: "Name", flex: 1 },
{ field: "isCompleted", headerName: "Completed", type: "boolean", width: 120 },
{ field: "createdAt", headerName: "Created", type: "dateTime", width: 180 },
];
function TodoGrid() {
const { data: todos } = useLiveQuery((query) =>
query.from({ todos: todoCollection })
);
return (
<DataGridPremium
rows={todos}
columns={columns}
getRowId={(row) => row.id}
autoHeight
/>
);
}
```
### Row actions with RouterGridActionsCellItem
```typescript
import { RouterGridActionsCellItem } from "wcz-layout/components";
import EditIcon from "@mui/icons-material/Edit";
import DeleteIcon from "@mui/icons-material/Delete";
import type { GridColDef } from "@mui/x-data-grid-premium";
const columns: GridColDef<Todo>[] = [
{ field: "name", headerName: "Name", flex: 1 },
{
field: "actions",
type: "actions",
width: 100,
getActions: (params) => [
<RouterGridActionsCellItem
key="edit"
icon={<EditIcon />}
label="Edit"
to="/todos/edit/$id"
params={{ id: params.row.id }}
/>,
<RouterGridActionsCellItem
key="delete"
icon={<DeleteIcon />}
label="Delete"
onClick={() => handleDelete(params.row)}
showInMenu
/>,
],
},
];
```
`RouterGridActionsCellItem` wraps MUI's `GridActionsCellItem` with TanStack Router's `createLink` for type-safe SPA navigation.
### ChipInputCell for array/tag columns
```typescript
import { ChipInputCell } from "wcz-layout/components";
import type { GridColDef } from "@mui/x-data-grid-premium";
const columns: GridColDef<Todo>[] = [
{
field: "tags",
headerName: "Tags",
flex: 1,
renderCell: (params) => <ChipInputCell params={params} />,
},
];
```
For complex objects (not plain strings), provide `getLabel`:
```typescript
renderCell: (params) => (
<ChipInputCell
params={params}
getLabel={(item) => item.displayName}
slotProps={{ size: "small", color: "primary" }}
/>
),
```
`ChipInputCell` renders a horizontal scrollable stack of `Chip` components. It handles both scalar and array values automatically.
### EditableColumnHeader
```typescript
import { EditableColumnHeader } from "wcz-layout/components";
const columns: GridColDef<Todo>[] = [
{
field: "name",
headerName: "Name",
flex: 1,
editable: true,
renderHeader: (params) => <EditableColumnHeader {...params} />,
},
];
```
Renders the column header text with a trailing pencil (Edit) icon to visually indicate editable columns. Purely visual — no interaction.
## Common Mistakes
### HIGH Using DataGrid instead of DataGridPremium
Wrong:
```typescript
import { DataGrid } from "@mui/x-data-grid";
```
Correct:
```typescript
import { DataGridPremium } from "@mui/x-data-grid-premium";
```
The library peer-depends on `@mui/x-data-grid-premium`. Using the community `DataGrid` loses Premium features like column grouping, row grouping, tree data, and aggregation.
Source: package.json peerDependencies
### HIGH Using GridActionsCellItem instead of RouterGridActionsCellItem
Wrong:
```typescript
import { GridActionsCellItem } from "@mui/x-data-grid-premium";
<GridActionsCellItem
icon={<EditIcon />}
label="Edit"
onClick={() => navigate({ to: `/todos/${id}` })}
/>
```
Correct:
```typescript
import { RouterGridActionsCellItem } from "wcz-layout/components";
<RouterGridActionsCellItem
icon={<EditIcon />}
label="Edit"
to="/todos/edit/$id"
params={{ id }}
/>
```
Plain `GridActionsCellItem` doesn't support TanStack Router navigation. `RouterGridActionsCellItem` wraps it with `createLink` for type-safe routing without manual `onClick` + `navigate`.
Source: wcz-layout:src/components/router/RouterGridActionsCellItem.tsx
### MEDIUM Not passing getLabel to ChipInputCell for complex objects
Wrong:
```typescript
// params.value is Array<{ id: string; name: string }>
<ChipInputCell params={params} />
// Renders [object Object] chips
```
Correct:
```typescript
<ChipInputCell
params={params}
getLabel={(item) => item.name}
/>
```
`ChipInputCell` defaults `getLabel` to identity (value as-is). For objects, you must provide `getLabel` to extract the display string.
Source: wcz-layout:src/components/data-grid/ChipInputCell.tsx
### HIGH Tension: MUI component API vs. TanStack Router types
`RouterGridActionsCellItem` merges MUI grid action props with TanStack Router `LinkProps`. Use `to` + `params` for internal navigation. Using `onClick` + `navigate` bypasses the type-safe link and router prefetching.
See also: skills/ui-pages/SKILL.md § Common Mistakes
See also:
- skills/tanstack-db-collections/SKILL.md — Grid rows come from useLiveQuery results.
- skills/ui-pages/SKILL.md — Grid pages follow the same routing patterns.