Claude
Skills
Sign in
Back

data-grid

Included with Lifetime
$97 forever

MUI X DataGrid configuration, server-side integration, and optimization

General

What this skill does


# MUI X DataGrid

## Package Tiers

| Package | Import | Features |
|---------|--------|---------|
| `@mui/x-data-grid` | `DataGrid` | Sorting, filtering, pagination, export (free, MIT) |
| `@mui/x-data-grid-pro` | `DataGridPro` | Column pinning, row grouping, master-detail, infinite scroll |
| `@mui/x-data-grid-premium` | `DataGridPremium` | Aggregation, pivoting, Excel export, row spanning |

Always import `GridColDef` and the grid from the same package.

---

## Basic Setup

```tsx
import { DataGrid, GridColDef } from '@mui/x-data-grid';
import Chip from '@mui/material/Chip';
import Box from '@mui/material/Box';

interface User {
  id: number;
  name: string;
  email: string;
  role: string;
  createdAt: string;
  active: boolean;
}

const columns: GridColDef<User>[] = [
  { field: 'id', headerName: 'ID', width: 80 },
  { field: 'name', headerName: 'Name', width: 180, flex: 1 },
  { field: 'email', headerName: 'Email', width: 220 },
  { field: 'role', headerName: 'Role', width: 120 },
  {
    field: 'createdAt',
    headerName: 'Created',
    width: 140,
    type: 'date',
    valueGetter: (value) => new Date(value),        // convert string to Date
    valueFormatter: (value: Date) =>
      value?.toLocaleDateString('en-US', { dateStyle: 'medium' }),
  },
  {
    field: 'active',
    headerName: 'Status',
    width: 100,
    type: 'boolean',
    renderCell: ({ value }) => (
      <Chip
        label={value ? 'Active' : 'Inactive'}
        color={value ? 'success' : 'default'}
        size="small"
      />
    ),
  },
];

function UsersGrid({ rows }: { rows: User[] }) {
  return (
    <Box sx={{ height: 600, width: '100%' }}>
      <DataGrid
        rows={rows}
        columns={columns}
        initialState={{
          pagination: { paginationModel: { pageSize: 25 } },
          sorting: { sortModel: [{ field: 'createdAt', sort: 'desc' }] },
        }}
        pageSizeOptions={[10, 25, 50, 100]}
        checkboxSelection
        disableRowSelectionOnClick
        density="compact"                   // 'compact' | 'standard' | 'comfortable'
        getRowId={(row) => row.id}          // only needed if row.id is not the key
      />
    </Box>
  );
}
```

---

## GridColDef Reference

```tsx
const col: GridColDef = {
  field: 'fieldName',          // must match row object key
  headerName: 'Display Name',
  description: 'Tooltip on header hover',
  width: 150,                  // fixed px width
  minWidth: 100,
  maxWidth: 300,
  flex: 1,                     // fill remaining space (like CSS flex-grow)
  type: 'string',              // 'string' | 'number' | 'date' | 'dateTime' | 'boolean' | 'singleSelect' | 'actions'
  align: 'left',               // 'left' | 'right' | 'center'
  headerAlign: 'left',
  sortable: true,
  filterable: true,
  hideable: true,
  pinnable: true,              // Pro/Premium only
  editable: false,

  // Transform raw value for display/sorting (not for renderCell)
  valueGetter: (value, row) => `${row.firstName} ${row.lastName}`,

  // Format value for display (runs after valueGetter)
  valueFormatter: (value: number) => `$${value.toFixed(2)}`,

  // Custom cell renderer — receives GridRenderCellParams
  renderCell: (params) => (
    <Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
      <Avatar src={params.row.avatar} sx={{ width: 24, height: 24 }} />
      {params.value}
    </Box>
  ),

  // Custom header renderer
  renderHeader: (params) => (
    <strong>{params.colDef.headerName} <span aria-hidden>*</span></strong>
  ),
};
```

### Actions column

```tsx
import { GridActionsCellItem, GridColDef } from '@mui/x-data-grid';

const actionsColumn: GridColDef = {
  field: 'actions',
  type: 'actions',
  headerName: 'Actions',
  width: 100,
  getActions: (params) => [
    <GridActionsCellItem
      key="edit"
      icon={<EditIcon />}
      label="Edit"
      onClick={() => handleEdit(params.row)}
    />,
    <GridActionsCellItem
      key="delete"
      icon={<DeleteIcon />}
      label="Delete"
      onClick={() => handleDelete(params.id)}
      showInMenu           // show in overflow menu instead of inline
    />,
  ],
};
```

---

## Client-Side Sorting, Filtering, Pagination

Client-side is the default. All three happen automatically — just provide `rows` and
`columns`. Customise with `initialState` or controlled props.

```tsx
import { GridSortModel, GridFilterModel } from '@mui/x-data-grid';

// Controlled sort
const [sortModel, setSortModel] = React.useState<GridSortModel>([
  { field: 'name', sort: 'asc' },
]);

<DataGrid
  rows={rows}
  columns={columns}
  sortModel={sortModel}
  onSortModelChange={setSortModel}
/>

// Controlled filter
const [filterModel, setFilterModel] = React.useState<GridFilterModel>({
  items: [{ field: 'role', operator: 'equals', value: 'admin' }],
});

<DataGrid
  rows={rows}
  columns={columns}
  filterModel={filterModel}
  onFilterModelChange={setFilterModel}
/>
```

---

## Server-Side Pagination, Sorting, and Filtering

Set `paginationMode`, `filterMode`, and `sortingMode` to `"server"`. Provide `rowCount`
so the grid knows total records. Fetch data whenever the model changes.

```tsx
import {
  DataGrid,
  GridSortModel,
  GridFilterModel,
  GridPaginationModel,
} from '@mui/x-data-grid';

function ServerGrid() {
  const [rows, setRows] = React.useState<User[]>([]);
  const [rowCount, setRowCount] = React.useState(0);
  const [loading, setLoading] = React.useState(false);

  const [paginationModel, setPaginationModel] = React.useState<GridPaginationModel>({
    page: 0,
    pageSize: 25,
  });
  const [sortModel, setSortModel] = React.useState<GridSortModel>([]);
  const [filterModel, setFilterModel] = React.useState<GridFilterModel>({ items: [] });

  // Fetch whenever any model changes
  React.useEffect(() => {
    let active = true;
    setLoading(true);

    fetchUsers({
      page: paginationModel.page,
      pageSize: paginationModel.pageSize,
      sort: sortModel,
      filter: filterModel,
    }).then((result) => {
      if (active) {
        setRows(result.rows);
        setRowCount(result.total);
        setLoading(false);
      }
    });

    return () => { active = false; };
  }, [paginationModel, sortModel, filterModel]);

  return (
    <Box sx={{ height: 600, width: '100%' }}>
      <DataGrid
        rows={rows}
        columns={columns}
        rowCount={rowCount}
        loading={loading}
        // Server-side modes
        paginationMode="server"
        sortingMode="server"
        filterMode="server"
        // Controlled models
        paginationModel={paginationModel}
        onPaginationModelChange={setPaginationModel}
        sortModel={sortModel}
        onSortModelChange={setSortModel}
        filterModel={filterModel}
        onFilterModelChange={(model) => {
          setFilterModel(model);
          // Reset to page 0 on filter change
          setPaginationModel((prev) => ({ ...prev, page: 0 }));
        }}
        pageSizeOptions={[25, 50, 100]}
        keepNonExistentRowsSelected     // preserve selection across pages
      />
    </Box>
  );
}
```

---

## Editable Grid

```tsx
import {
  DataGrid,
  GridRowId,
  GridRowModel,
  GridRowModesModel,
  GridRowModes,
  GridRowEditStopReasons,
  GridEventListener,
} from '@mui/x-data-grid';

function EditableGrid({ initialRows }: { initialRows: User[] }) {
  const [rows, setRows] = React.useState(initialRows);
  const [rowModesModel, setRowModesModel] = React.useState<GridRowModesModel>({});

  const handleRowEditStop: GridEventListener<'rowEditStop'> = (params, event) => {
    if (params.reason === GridRowEditStopReasons.rowFocusOut) {
      event.defaultMuiPrevented = true; // don't save on blur, only on Enter
    }
  };

  const handleSave = (id: GridRowId) => {
    setRowModesModel((prev) => ({
      ...prev,
      [id]: { mode: GridRowModes.View },
    }));
  };

  const handleCancel = (id: GridRowId) => {
    setRowModesModel((prev) => ({
      ...prev,
      [id]: { mode: GridRowModes

Related in General