@opencorestack/opengridx 2.1.0 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (225) hide show
  1. package/CHANGELOG.md +399 -0
  2. package/README.md +95 -72
  3. package/dist/index.d.ts +590 -131
  4. package/dist/opengridx.css +1 -1
  5. package/dist/opengridx.es.js +7891 -5631
  6. package/dist/opengridx.es.js.map +1 -1
  7. package/dist/opengridx.umd.js +17 -23
  8. package/dist/opengridx.umd.js.map +1 -1
  9. package/docs/API_REFERENCE.md +348 -166
  10. package/docs/README.md +6 -1
  11. package/docs/architecture/datagrid-orchestration.md +81 -0
  12. package/docs/architecture/grid-row-meta.md +102 -0
  13. package/docs/architecture/use-grid-columns.md +128 -0
  14. package/docs/architecture/use-grid-controlled-state.md +157 -0
  15. package/docs/architecture/use-grid-row-pipeline.md +120 -0
  16. package/docs/architecture/use-grid-scroll-sync.md +111 -0
  17. package/docs/architecture/use-grid-state-snapshot.md +90 -0
  18. package/docs/architecture/use-grid-virtualization.md +115 -0
  19. package/docs/architecture/use-grid-visible-rows.md +85 -0
  20. package/docs/assets/banner-alt.png +0 -0
  21. package/docs/assets/banner.png +0 -0
  22. package/docs/assets/hero.png +0 -0
  23. package/docs/assets/logo.png +0 -0
  24. package/docs/components/aggregation-footer.md +15 -10
  25. package/docs/components/cell.md +16 -6
  26. package/docs/components/column-group-header.md +55 -28
  27. package/docs/components/column-resize.md +17 -13
  28. package/docs/components/column-visibility.md +6 -7
  29. package/docs/components/datagrid.md +15 -13
  30. package/docs/components/empty-state.md +2 -1
  31. package/docs/components/error-overlay.md +12 -7
  32. package/docs/components/filter-panel.md +28 -8
  33. package/docs/components/header.md +28 -9
  34. package/docs/components/pagination.md +14 -8
  35. package/docs/components/row.md +21 -5
  36. package/docs/components/toolbar.md +27 -9
  37. package/docs/components/tooltip.md +16 -7
  38. package/docs/customization/slots-api.md +90 -38
  39. package/docs/customization/theming.md +66 -18
  40. package/docs/features/aggregation-pivot.md +75 -9
  41. package/docs/features/cell-spanning.md +80 -125
  42. package/docs/features/clipboard.md +41 -16
  43. package/docs/features/custom-pagination.md +38 -18
  44. package/docs/features/data-source.md +36 -13
  45. package/docs/features/editing-reordering.md +125 -16
  46. package/docs/features/export-guide.md +126 -39
  47. package/docs/features/filtering.md +44 -6
  48. package/docs/features/infinite-scroll.md +54 -46
  49. package/docs/features/keyboard-navigation.md +83 -0
  50. package/docs/features/list-view.md +58 -5
  51. package/docs/features/loading-states.md +18 -20
  52. package/docs/features/master-detail.md +18 -5
  53. package/docs/features/pdf-export.md +72 -19
  54. package/docs/features/pinning.md +24 -5
  55. package/docs/features/selection.md +50 -10
  56. package/docs/features/sorting-pagination.md +64 -14
  57. package/docs/features/state-persistence.md +78 -10
  58. package/docs/features/toolbar-customization.md +26 -17
  59. package/docs/features/tree-data-grouping.md +36 -8
  60. package/docs/features/virtualization.md +37 -14
  61. package/docs/migration/v1-to-v2.md +115 -0
  62. package/docs/migration/v2-to-v3.md +1233 -0
  63. package/docs/performance.md +124 -0
  64. package/docs/roadmap.md +5 -5
  65. package/lib/components/Cell/Cell.css +17 -1
  66. package/lib/components/Cell/Cell.tsx +129 -57
  67. package/lib/components/Cell/CellErrorBoundary.tsx +12 -6
  68. package/lib/components/Cell/GridEditInputCell.tsx +114 -41
  69. package/lib/components/ColumnGroupHeader/ColumnGroupHeader.css +7 -1
  70. package/lib/components/ColumnResizeHandle/ColumnResizeHandle.css +15 -2
  71. package/lib/components/ColumnResizeHandle/ColumnResizeHandle.tsx +104 -38
  72. package/lib/components/ColumnResizeHandle/clampResizeWidth.ts +13 -0
  73. package/lib/components/ColumnVisibilityPanel/ColumnVisibilityPanel.css +6 -0
  74. package/lib/components/ColumnVisibilityPanel/ColumnVisibilityPanel.tsx +21 -13
  75. package/lib/components/DataGrid/DataGrid.css +85 -12
  76. package/lib/components/DataGrid/DataGrid.tsx +582 -876
  77. package/lib/components/DataGrid/GridAggregationFooter.tsx +53 -17
  78. package/lib/components/DataGrid/GridErrorOverlay.tsx +15 -12
  79. package/lib/components/DataGrid/GridListView.tsx +165 -24
  80. package/lib/components/DataGrid/GridLiveRegion.tsx +31 -0
  81. package/lib/components/DataGrid/GridLoadingOverlay.tsx +27 -0
  82. package/lib/components/DataGrid/GridPaginationArea.tsx +44 -0
  83. package/lib/components/DataGrid/GridPinnedRows.tsx +62 -11
  84. package/lib/components/DataGrid/GridStandaloneColumnPanel.tsx +40 -38
  85. package/lib/components/DataGrid/GridToolbarSlot.tsx +51 -0
  86. package/lib/components/DataGrid/GridVirtualRows.tsx +40 -24
  87. package/lib/components/DetailPanel/DetailPanel.css +0 -6
  88. package/lib/components/DetailPanel/DetailPanel.tsx +34 -5
  89. package/lib/components/DetailPanel/DetailPanelContent.tsx +17 -0
  90. package/lib/components/FilterPanel/FilterPanel.css +13 -2
  91. package/lib/components/FilterPanel/FilterPanel.tsx +272 -99
  92. package/lib/components/Header/ColumnMenu.tsx +91 -39
  93. package/lib/components/Header/Header.css +6 -3
  94. package/lib/components/Header/Header.tsx +181 -160
  95. package/lib/components/ListView/ListView.css +25 -0
  96. package/lib/components/ListView/ListViewRow.tsx +76 -10
  97. package/lib/components/Pagination/Pagination.tsx +15 -7
  98. package/lib/components/Row/Row.tsx +177 -77
  99. package/lib/components/Toolbar/GlobalSearch.css +6 -3
  100. package/lib/components/Toolbar/GlobalSearch.tsx +26 -27
  101. package/lib/components/Toolbar/GridToolbar.css +12 -11
  102. package/lib/components/Toolbar/GridToolbar.tsx +133 -89
  103. package/lib/components/Toolbar/PivotPanel.tsx +89 -49
  104. package/lib/components/Tooltip/Tooltip.css +20 -0
  105. package/lib/components/Tooltip/Tooltip.tsx +68 -35
  106. package/lib/components/ui/Button.tsx +3 -0
  107. package/lib/components/ui/Checkbox.tsx +2 -1
  108. package/lib/components/ui/ExpandIcon.css +0 -9
  109. package/lib/components/ui/ExpandIcon.tsx +4 -1
  110. package/lib/hooks/core/gridApiPlaceholder.ts +34 -0
  111. package/lib/hooks/core/gridToolbarHostContext.ts +14 -0
  112. package/lib/hooks/core/useDataGrid.ts +115 -173
  113. package/lib/hooks/core/useGridAggregationApi.ts +72 -0
  114. package/lib/hooks/core/useGridApiMethods.ts +115 -0
  115. package/lib/hooks/core/useGridApiRef.ts +19 -4
  116. package/lib/hooks/core/useGridApiRefBinding.ts +18 -0
  117. package/lib/hooks/core/useGridAriaRows.ts +38 -0
  118. package/lib/hooks/core/useGridClipboardApi.ts +38 -0
  119. package/lib/hooks/core/useGridColumnLookup.ts +30 -0
  120. package/lib/hooks/core/useGridColumns.tsx +279 -76
  121. package/lib/hooks/core/useGridColumnsPanel.ts +77 -0
  122. package/lib/hooks/core/useGridControlledState.ts +99 -6
  123. package/lib/hooks/core/useGridDetailPanel.ts +51 -0
  124. package/lib/hooks/core/useGridDevWarnings.ts +104 -5
  125. package/lib/hooks/core/useGridFocusHandlers.ts +50 -0
  126. package/lib/hooks/core/useGridGroupingColumn.ts +62 -0
  127. package/lib/hooks/core/useGridHeaderHandlers.ts +92 -0
  128. package/lib/hooks/core/useGridHierarchy.ts +81 -0
  129. package/lib/hooks/core/useGridKeyboardNavigation.ts +447 -243
  130. package/lib/hooks/core/useGridLiveRowSelection.ts +67 -0
  131. package/lib/hooks/core/useGridPageCorrection.ts +55 -0
  132. package/lib/hooks/core/useGridRowIdOf.ts +32 -0
  133. package/lib/hooks/core/useGridRowInteractions.ts +81 -0
  134. package/lib/hooks/core/useGridRowPipeline.ts +69 -39
  135. package/lib/hooks/core/useGridRowSelection.ts +91 -0
  136. package/lib/hooks/core/useGridScrollSync.ts +80 -32
  137. package/lib/hooks/core/useGridScrollToIndexesApi.ts +45 -0
  138. package/lib/hooks/core/useGridStateSnapshot.ts +40 -5
  139. package/lib/hooks/core/useGridThemeDimensions.ts +49 -0
  140. package/lib/hooks/core/useGridToolbarProps.ts +97 -0
  141. package/lib/hooks/core/useGridViewport.ts +38 -0
  142. package/lib/hooks/core/useGridViewportSize.ts +26 -0
  143. package/lib/hooks/core/useGridVisibleRows.ts +17 -5
  144. package/lib/hooks/core/useLayout.ts +215 -195
  145. package/lib/hooks/core/useRowsScrollEndLatch.ts +41 -0
  146. package/lib/hooks/core/useStableColumns.ts +34 -0
  147. package/lib/hooks/features/useAggregation.ts +82 -51
  148. package/lib/hooks/features/useColumnGroupReorderGuard.ts +34 -0
  149. package/lib/hooks/features/useDetailPanelHeights.ts +29 -0
  150. package/lib/hooks/features/useGridClipboard.ts +133 -73
  151. package/lib/hooks/features/useGridDataSource.ts +354 -128
  152. package/lib/hooks/features/useGridEditing.ts +211 -51
  153. package/lib/hooks/features/useGridPivot.ts +92 -0
  154. package/lib/hooks/features/useGridSpanRenderWindow.ts +104 -0
  155. package/lib/hooks/features/useGridSpanning.ts +410 -306
  156. package/lib/hooks/features/usePivot.ts +0 -0
  157. package/lib/hooks/features/useServerTreeChildren.ts +50 -0
  158. package/lib/hooks/useColumnReorder.ts +38 -44
  159. package/lib/hooks/useRowGrouping.ts +298 -160
  160. package/lib/hooks/useRowReorder.ts +62 -31
  161. package/lib/hooks/useTreeData.ts +287 -220
  162. package/lib/index.ts +28 -2
  163. package/lib/state/index.ts +1 -0
  164. package/lib/state/types.ts +7 -1
  165. package/lib/state/useGridStateStorage.ts +88 -29
  166. package/lib/theme/DataGridThemeProvider.tsx +143 -38
  167. package/lib/theme/gridThemeContext.ts +5 -0
  168. package/lib/theme/index.ts +5 -0
  169. package/lib/theme/presets.ts +5 -4
  170. package/lib/theme/types.ts +40 -2
  171. package/lib/types/index.ts +313 -116
  172. package/lib/utils/aggregation/index.ts +119 -24
  173. package/lib/utils/aria/index.ts +40 -0
  174. package/lib/utils/columnGroups.ts +110 -0
  175. package/lib/utils/columnLookup.ts +33 -0
  176. package/lib/utils/columnWidth.ts +22 -0
  177. package/lib/utils/dataSource/index.ts +46 -0
  178. package/lib/utils/detailPanel.ts +66 -0
  179. package/lib/utils/dragData.ts +44 -0
  180. package/lib/utils/editing/index.ts +30 -0
  181. package/lib/utils/export/exportShared.ts +197 -0
  182. package/lib/utils/export/exportToExcelAdvanced.ts +278 -139
  183. package/lib/utils/export/exportToPdf.ts +143 -92
  184. package/lib/utils/export/groupLabel.ts +14 -0
  185. package/lib/utils/export/index.ts +278 -272
  186. package/lib/utils/export/pdfText.ts +50 -0
  187. package/lib/utils/filtering/index.ts +277 -148
  188. package/lib/utils/focus/index.ts +115 -0
  189. package/lib/utils/gridApiRows.ts +35 -0
  190. package/lib/utils/gridModes.ts +77 -0
  191. package/lib/utils/grouping/groupedExportRows.ts +91 -0
  192. package/lib/utils/pagination/index.ts +56 -0
  193. package/lib/utils/pinning/index.ts +77 -33
  194. package/lib/utils/pivot/index.ts +368 -0
  195. package/lib/utils/scroll/index.ts +55 -5
  196. package/lib/utils/scroll/scrollEnd.ts +18 -0
  197. package/lib/utils/sorting/index.ts +154 -30
  198. package/lib/utils/syntheticRows.ts +12 -0
  199. package/lib/utils/values.ts +206 -0
  200. package/lib/utils/viewport.ts +14 -0
  201. package/llms.txt +261 -164
  202. package/package.json +13 -5
  203. package/lib/components/ColumnGroupHeader/ColumnGroupHeader.tsx +0 -220
  204. package/lib/components/ColumnVisibilityPanel/ColumnVisibilityPanel.test.tsx +0 -85
  205. package/lib/components/DataGrid/DataGrid.defects.test.tsx +0 -103
  206. package/lib/components/DataGrid/DataGrid.regression.test.tsx +0 -132
  207. package/lib/components/DataGrid/DataGrid.smoke.test.tsx +0 -58
  208. package/lib/components/DataGrid/DataGrid.v2.test.tsx +0 -127
  209. package/lib/components/DataGrid/DataGrid.virtualization.browser.test.tsx +0 -183
  210. package/lib/components/Header/Header.test.tsx +0 -135
  211. package/lib/components/Pagination/Pagination.test.tsx +0 -64
  212. package/lib/hooks/core/useDataGrid.regression.test.ts +0 -66
  213. package/lib/hooks/core/useGridControlledState.test.ts +0 -86
  214. package/lib/hooks/core/useGridKeyboardNavigation.test.ts +0 -176
  215. package/lib/hooks/core/useGridRowPipeline.test.ts +0 -117
  216. package/lib/hooks/features/useAggregation.test.ts +0 -175
  217. package/lib/hooks/features/usePivot.test.ts +0 -202
  218. package/lib/hooks/useRowGrouping.test.ts +0 -298
  219. package/lib/hooks/useTreeData.test.ts +0 -83
  220. package/lib/utils/aggregation/aggregation.test.ts +0 -16
  221. package/lib/utils/export/exportToExcelAdvanced.test.ts +0 -109
  222. package/lib/utils/export/exportToPdf.test.ts +0 -120
  223. package/lib/utils/export/groupedExport.test.ts +0 -144
  224. package/lib/utils/filtering/filtering.test.ts +0 -178
  225. package/lib/utils/sorting/sorting.test.ts +0 -88
package/CHANGELOG.md CHANGED
@@ -5,6 +5,405 @@
5
5
 
6
6
  ---
7
7
 
8
+ ## [3.0.1] — 2026-09-29
9
+
10
+ Fixes from a smoke test in a real application (Chromium, Firefox and WebKit).
11
+
12
+ ### Fixed
13
+
14
+ - **A grid without a `height` prop now fills its container.** Its root was auto-height, so inside a bounded flex layout (a wrapper with `flex: 1; min-height: 0`, with or without `DataGridThemeProvider`) it grew to fit every row and rendered all of them; 50,000 rows froze the tab. The root now gets `height: 100%` and, as a flex item, `flex: 1 1 auto; min-height: 0` (class `ogx--fill`) when neither `height`, `style.height` nor `autoHeight` is set. In an auto-height container it still grows to fit, as before. An explicit `height` is never stretched.
15
+ - **The unbounded-container development warning** is only logged when the viewport is at least as tall as the rows it renders, and names the fixes: a definite container height, `min-height: 0` on every flex or grid ancestor up to the sized one, a `height` prop, or `autoHeight`.
16
+ - **The list view warns in development when it renders more than 2,000 items.** It does not virtualize; README and the list-view guide now say so and recommend pagination.
17
+ - **The whole column resize handle can be grabbed.** The 8px handle straddled the header cell border and the cell's `overflow: hidden` clipped half of it, leaving 3–4px in every engine. It now lies inside its column against the resizing edge (also in the column-group header layout and for right-pinned columns).
18
+ - **Right-pinned columns sit at the right edge** when the columns are narrower than the grid, in the header, column-group rows, body, pinned rows and aggregation footer. They used to follow the last unpinned column, leaving a gap on their right.
19
+ - **List view, Firefox:** the rows container was a Tab stop of its own (Firefox makes scroll containers focusable), so Tab landed on it instead of the focused row. It now has `tabIndex={-1}`.
20
+
21
+ ### Added
22
+
23
+ - **Typed `apiRef` row getters.** `GridApi<R>` (default `GridRowModel`) and `useGridApiRef<R>()` type `getRow`, `getAllRows`, `getVisibleRows` and `getAllFilteredRows` as your row type. `DataGridProps.apiRef` accepts a typed or an untyped ref, so existing code compiles unchanged.
24
+
25
+ ### Styling and DOM (check custom CSS)
26
+
27
+ - New root class `ogx--fill` (`height: 100%; flex: 1 1 auto; min-height: 0`) when no `height`, `style.height` or `autoHeight` is set. CSS that sets the grid's height on `.ogx` still wins only if it is more specific or passed as `style.height` / `height`.
28
+ - `.ogx-column-resize-handle` is `right: 0` (was `-4px`) with `justify-content: flex-end`; `.ogx-column-resize-handle--start` is `left: 0` (was `-4px`) with `flex-start`. The visible line stays on the column border.
29
+ - `.ogx__header-cell--pinned-right-first`, `.ogx__cell--pinned-right-first`, `.ogx__aggregation-cell--pinned-right-first` and the first right-pinned column-group cell get `margin-left: auto`; with right-pinned columns, `.ogx__content` is `max(100%, <total>px)` wide instead of the column total.
30
+ - `.ogx-list-view__rows` has `tabIndex="-1"`.
31
+
32
+ ### Testing
33
+
34
+ - The browser test suite and CI (deploy and publish workflows) run in Chromium, Firefox and WebKit.
35
+
36
+ ### Documentation
37
+
38
+ - README `height` row, Getting Started, virtualization, theming, datagrid and pinning docs describe how the grid fills its container.
39
+ - PDF export: the `font` option is shown up front with a `₹` example, and the size and time of very large exports are documented (50,000 grouped rows ≈ 120 MB, 10–16 s on the main thread); use CSV or `.xlsx` for large exports.
40
+ - README: a rejected `processRowUpdate` keeps the cell in edit mode with the typed value and calls `onProcessRowUpdateError`.
41
+
42
+ ---
43
+
44
+ ## [3.0.0] — 2026-09-24
45
+
46
+ A correctness release: every feature area was audited against its documentation and the grid's own behaviour. Most changes are bug fixes, but many of them change observable output (formatted text, exported files, callback indices, request ranges), which is why this is a major version.
47
+
48
+ **Upgrading from 2.x: read [docs/migration/v2-to-v3.md](docs/migration/v2-to-v3.md).** It starts with a table that maps what your app uses to the sections you need.
49
+
50
+ **React 18 users:** 2.1.0 crashed on React 18 (the build bundled React 19's JSX runtime). 3.0.0 works on React 18 and 19 again; see *Fixed → Build & SSR*.
51
+
52
+ ### Breaking
53
+
54
+ - **The underscore hierarchy fields are no longer added to rows.** `_hasChildren`, `_treeDepth`, `_isExpanded`, `_groupingField`, `_groupingValue`, `_descendantCount` and `_isGroupRow` (deprecated since 1.1) are gone at runtime; use `params.rowMeta`. TypeScript does not flag reads of them, because `GridRowModel` has an index signature.
55
+ - **`params.row` under row grouping and tree data is now the consumer's own row object**, not a per-render copy. Code that mutated `params.row` in a render callback now mutates the source data. As a side effect, rows are no longer re-created on every render.
56
+ - **`getRowId` no longer writes an `id` onto your rows.** Rows are stored untouched everywhere (grid, callbacks, `processRowUpdate`, `apiRef`), so `row.id === getRowId(row)` no longer holds. Pass `getRowId` to export functions when exporting `selectedRows`.
57
+ - **Grouped-export default labels in `exportToExcelAdvanced` now match the grid.** Without a `groupingValueFormatter`, group headers read `"field: value"` (the grid's documented default) instead of `"Header: value"`. Set `groupingValueFormatter` on the grouping column to control the label in the grid and in every export format.
58
+ - **Cells are formatted by column `type` when there is no `valueFormatter`:** `date` shows `toLocaleDateString()`, `boolean` shows Yes/No, `singleSelect` shows the option label and `image` renders an `<img>`. This applies to cells, `params.formattedValue`, list view and text exports.
59
+ - **Empty filter values no longer filter**, the quick filter searches only visible filterable columns, and the toolbar search box splits its text into words that must all match.
60
+ - **Aggregation ignores blank strings, booleans and arrays** in `sum` / `avg` / `min` / `max`, and `min` / `max` over dates return a `Date` (was epoch milliseconds).
61
+ - **CSV files start with a UTF-8 BOM and text that looks like a formula gets a leading `'`** (CSV and basic Excel). Opt out with `bom: false` / `escapeFormulas: false`.
62
+ - **A non-empty `selectedRows` now wins over `groupedRows`** in every export: the selection is exported flat and totals are recomputed over it.
63
+ - **`exportToExcel` always writes `.xls`**; a `.xlsx` file name is renamed with a warning (the file was always HTML, which Excel rejects under `.xlsx`).
64
+ - **Tab leaves the grid in one press** outside edit mode (it used to step through cells). While editing, Tab still moves to the next editable cell.
65
+ - **Index values changed meaning:** `colIndex` is absolute among visible data columns (was window-relative), bottom-pinned rows get `rowIndex` after the page rows (were 0..n), `onRowOrderChange` indices are positions in the `rows` prop (were page-local and sorted), and `onColumnOrderChange` indices are positions in the full column order.
66
+ - **`isCellEditable` now governs every way of starting an edit** (double-click, Enter, Tab) and `aria-readonly`, not only Tab stops.
67
+ - **`processRowUpdate` is called when an edit is lost** (the cell scrolls out, is filtered or paged away, or another cell starts editing). Those edits used to be dropped.
68
+ - **Built-in editors commit the column's value type:** `singleSelect` commits the option value (not its string form), `date` commits a `Date` for `Date` cells and `null` when cleared.
69
+ - **Pinned columns render in `pinnedColumns.left` / `.right` order**, not column order.
70
+ - **Header and top-pinned rows are wrapped in `div.ogx__sticky-top`, bottom-pinned rows and the aggregation footer in `div.ogx__sticky-bottom`.** `.ogx__pinned-rows--top` / `--bottom` are no longer sticky themselves; custom CSS that targets them must move to the wrappers.
71
+ - **Group and pivot row ids changed format.** Row-grouping ids for non-string values, tree-data auto-parent ids and pivot row ids use new, collision-free formats; do not parse them.
72
+ - **`DataGridThemeProvider` pins a complete light or dark palette** chosen by the new `GridTheme.mode`, whatever the operating-system colour scheme. A provider-wrapped grid no longer switches with the OS.
73
+ - **Grid buttons have `type="button"`** (including the exported `Button`), so they never submit an enclosing `<form>`. Pass `type="submit"` explicitly where you want a submit button.
74
+ - **`apiRef.current.copySelectedRows()` rejects when the clipboard write fails** (it resolved and logged).
75
+ - **`dataSource` requests changed:** `getRows` is now called with all-client modes, infinite scroll requests the gap after the loaded rows, and tree children are requested with `endRow: Number.MAX_SAFE_INTEGER` (was `-1`).
76
+ - **Column resizing uses pointer events** (tests that simulate `mousedown` / `mousemove` must use pointer events) and no longer caps widths at 1000px.
77
+ - **Removed `GridThemeSkeleton.darkBaseColor` and `darkHighlightColor`**, which had no effect.
78
+
79
+ ### Security
80
+
81
+ - `printGrid` escapes the title, cell values, image URLs and alt text, and error messages in the same-origin print window, and only renders images from `http(s)`, `data:image`, `blob:` and relative URLs.
82
+ - `exportToCsv` and `exportToExcel` neutralise spreadsheet formula injection: text starting with `=`, `+`, `-`, `@`, tab or carriage return gets a leading `'`. New option `escapeFormulas` (default `true`).
83
+ - `exportToExcelAdvanced` writes object values as text, so `{ formula }`, `{ hyperlink }`, `{ richText }` or `{ error }` objects in row data can no longer become live cells or links.
84
+ - Grouped `exportToJson` no longer leaks `exportable: false` columns through subtotals and the grand total.
85
+
86
+ ### Fixed
87
+
88
+ #### Export
89
+
90
+ - Grouped CSV, basic Excel, JSON, print and PDF exports ignored `groupingValueFormatter` for group-header labels; all exporters now share one label rule, and `getGroupedExportRows()` entries carry the grid's label as `groupLabel`.
91
+ - `exportToExcelAdvanced` dates were shifted by the UTC offset (a day early east of UTC).
92
+ - NaN, Infinity and Invalid Date values produced a corrupt xlsx file.
93
+ - `selectedRows` was ignored when `groupedRows` was also passed; totals are now recomputed over the selection.
94
+ - Exporting a large selection froze the tab.
95
+ - CSV did not quote values containing the configured delimiter or a bare carriage return.
96
+ - `count` / `unique` totals were formatted as currency or dates.
97
+ - A `valueFormatter` that reads other row fields or expects a `Date` aborted exports with totals.
98
+ - The first column's aggregate was replaced by the Subtotal / Grand Total / TOTAL label; the label is now prefixed to the value.
99
+ - Spacer columns (`isSpacer`) and grid system columns (`__checkbox_col__`, `__expand_col__`, `__reorder_col__`, `__group__`) passed in `columns` were exported; they are always left out.
100
+ - A `valueFormatter` placeholder for missing values is exported, as the grid shows it.
101
+ - Basic Excel dropped leading zeros and mangled long numeric ids, and wrote invalid sheet names.
102
+ - `exportToExcelAdvanced`: `rows: 'selected'` sheets contain only the selection; invalid or duplicate sheet names no longer throw; `embedImage` follows `valueGetter` and falls back to the URL for SVG, WebP and AVIF; ISO date strings and numeric strings become native cells; integers have no trailing "."; totals and the summary sheet are numeric; striped rows have no gaps.
103
+ - PDF: non-Latin-1 text was garbled wholesale; `#fff` shorthand colours work; the row count is correct when `groupedRows` is `[]`; the filter summary reflects nested groups, OR and quick search, and wraps.
104
+ - JSON aggregation values are numbers, as documented.
105
+ - Print keeps group-row highlights on even rows.
106
+
107
+ #### Filtering & sorting
108
+
109
+ - Date operators `after`, `onOrAfter`, `before` and `onOrBefore` did not filter (every row passed, with a warning per row).
110
+ - Date `is` / `not` compared raw strings; they now match the local calendar day for `Date` values, ISO datetimes and epoch numbers.
111
+ - A filter item with no value filtered anyway (`>` meant `> 0`, `=` hid every row).
112
+ - Numeric filters treated blank cells as 0; `!=` treats empty cells consistently.
113
+ - A `singleSelect` filter set from the panel emptied the grid; the panel now offers the column's `valueOptions`.
114
+ - Opening the filter panel rewrote values (an `isAnyOf` array became `"a,b"`) and fired `onFilterModelChange`.
115
+ - Editing a panel row deleted filter groups and other conditions on the same column.
116
+ - Changing the operator right after typing lost the typed value, and a pending keystroke undid Clear all.
117
+ - `valueGetter` columns could not be sorted, filtered or quick-searched (including under tree data and row grouping).
118
+ - The quick filter matched the row id, hidden columns, non-column fields, `[object Object]` and `Date.toString()` text; it now matches what cells show.
119
+ - A multi-word toolbar search now matches words across columns.
120
+ - The row-grouping "Group" column appeared in the filter panel.
121
+ - Number columns holding numeric strings sort numerically; NaN and Invalid Date no longer break sorting; accented strings sort next to their base letter.
122
+ - Shift-click on a sorted column kept moving it to the end of the sort; column-menu Unsort / Asc / Desc cleared the other sort keys.
123
+ - The toolbar search box stole focus back on re-render.
124
+ - The boolean filter could not select "true" directly; the panel shows the real operator of programmatic items.
125
+ - `initialState.filter` was ignored; the toolbar search and Filters button did nothing without a `filterModel` prop.
126
+ - A `valueGetter` or `valueFormatter` that throws no longer crashes the grid once the column is sorted, filtered, quick-filtered, aggregated, grouped or pivoted, or shown in list view: the value reads as `undefined` and a dev warning is logged once per column.
127
+ - Text typed into the FilterPanel or the toolbar search box just before the panel closes is no longer lost.
128
+
129
+ #### Editing
130
+
131
+ - `isCellEditable` did not block double-click and Enter editing; rejected cells now carry `aria-readonly="true"`.
132
+ - `processRowUpdate` ran twice for one commit (Tab, or Enter then blur).
133
+ - A slow `processRowUpdate` closed an edit on another cell or discarded text typed meanwhile.
134
+ - Clicking inside an open editor committed and closed it; the dropdown editor was unusable with the mouse; clicks inside editors fired `onCellClick` / `onRowClick` and toggled selection.
135
+ - An edit was lost when its row scrolled out, was filtered or paged away, or another cell started editing; it is now committed.
136
+ - Committing one edit reverted other changes to the row and reset the server row count.
137
+ - Tree-data parent rows could not be edited by double-click; Enter opened a useless editor on row-grouping group rows.
138
+ - Committing by clicking a control outside the grid stole focus back.
139
+ - The `singleSelect` editor committed typed option values as strings and showed no empty choice for an empty or unknown value.
140
+ - The date editor was blank for `Date` and ISO datetime values and committed a different kind of value; clearing it commits `null`.
141
+ - With a custom `getRowId`, a `processRowUpdate` result without the grid's id was not applied.
142
+ - An inline `getRowId` function reverted committed edits on every parent re-render.
143
+ - `onRowDoubleClick` did not fire on editable cells.
144
+ - The boolean editor did not close on blur; IME composition Enter committed the edit; built-in editors had no accessible name.
145
+ - Double-clicking inside an editor discarded the typed value.
146
+ - A `processRowUpdate` that returns nothing is now reported clearly and the editor stays open.
147
+ - Enter-to-edit starts from the `valueGetter` value.
148
+ - Every cell re-rendered on every grid render.
149
+
150
+ #### Selection & apiRef
151
+
152
+ - `apiRef` methods `sortColumn`, `setFilterModel`, `setPage`, `setPageSize`, `selectRow` and `selectRows` did not change the grid or fire callbacks; `getSortModel`, `getFilterModel` and `getSelectedRows` returned stale values.
153
+ - `apiRef.current.getSelectedRows()` returned the previous selection inside `onRowSelectionModelChange`.
154
+ - `getVisibleColumns` included hidden columns and ignored display order; `getVisibleRows` and `getAllFilteredRows` omitted pinned rows; `getAllFilteredRows` missed rows under tree data and row grouping.
155
+ - `getGroupedExportRows()` dropped the rows of collapsed groups and ignored sort and filter.
156
+ - Select-all selected filtered-out rows, could not be undone with a `dataSource`, and the header checkbox showed the wrong state.
157
+ - `disableMultipleRowSelection` was ignored by checkboxes, Space and select-all.
158
+ - Selection kept the ids of rows that were removed from `rows`.
159
+ - `getRowId` overwrote the row's own `id` field (grid, `dataSource` rows and tree children).
160
+ - Duplicate row ids rendered one row twice.
161
+ - `onStateChange` looped with inline models; its payload now carries `density` and never contains `__group__`; `initialState.density` is honoured.
162
+ - `useGridStateStorage` crashed when storage is blocked, `clearState` was undone, and storage was written on every re-render.
163
+ - `useGridApiRef()` did not type-check against the `apiRef` prop under `@types/react` 18.
164
+ - Changing `rows` and `columns` together (or leaving pivot mode) ran the new columns against the old rows, crashing `valueGetter`s.
165
+ - A controlled `rowSelectionModel` holding an id that is no longer in `rows` fired `onRowSelectionModelChange` on every render and could loop; the pruned selection (and a corrected page) is now reported once, also under StrictMode.
166
+ - `getAggregationResult`, `getAggregationModel`, `getGroupedExportRows` and `scrollToIndexes` are available in a parent's `useLayoutEffect`.
167
+ - `getVisibleColumns` returns columns in render order (left-pinned, unpinned, right-pinned).
168
+ - `apiRef.selectRow` / `selectRows` ignore synthetic ids (group, subtotal, auto-parent and pivot Grand Total rows), and a call that does not change the selection fires nothing. The pivot Grand Total row cannot be selected.
169
+
170
+ #### Pagination & data source
171
+
172
+ - The pager total ignored the filter and counted pinned rows.
173
+ - Server pagination, sorting or filtering without a `dataSource` re-sliced, re-sorted or re-filtered the rows.
174
+ - The `rowCount` prop was read only at mount.
175
+ - The default page size could be missing from `pageSizeOptions`.
176
+ - `slots.footer` received the page length instead of the server total.
177
+ - Shrinking data left the grid on an empty page past the end; it now shows the last page and reports it through `onPaginationModelChange`.
178
+ - The rows-per-page select did not show a page size missing from `pageSizeOptions`, had a hard-coded accessible name, and showed "Infinity" for page size 0.
179
+ - Infinite scroll skipped rows when the page advanced quickly or while loading; it now requests the missing range without duplicates.
180
+ - Infinite scroll: changing sort, filter, `pageSize` or `dataSource` restarts from the first row and reports page 0.
181
+ - Server sort or filter with client pagination showed only the first page.
182
+ - A `dataSource` with the default (client) modes never loaded its rows.
183
+ - The error overlay's Retry reloaded the whole page; it now re-requests rows, and shows the message of any rejected object with a `message`.
184
+ - Stale responses overwrote newer ones.
185
+ - Inline `filterModel`, `sortModel`, `aggregationModel` or `dataSource` objects refetched on every render and wiped loaded infinite pages.
186
+ - An inline `rows={[]}` next to a `dataSource` wiped the fetched rows.
187
+ - "No Data" flashed before the first response, and the live region announced "Loading data... No Data".
188
+ - Server tree data: children now load with every row, keep the pager total, are not re-filtered or re-sorted under server modes, reload for expanded nodes after a refetch, and a failed children request collapses its node instead of covering the grid.
189
+ - `paginationMode="infinite"` combined with `pagination` sliced the rows.
190
+ - `loading` with rows present showed nothing; it now shows a progress bar (or `slots.loadingOverlay`) over the rows.
191
+ - A `dataSource` response that cannot be processed shows the error overlay instead of loading forever.
192
+ - Row grouping with a `paginationMode="server"` `dataSource` loads every row in one request (with a dev warning) instead of grouping only the first page.
193
+
194
+ #### Row grouping & tree data
195
+
196
+ - The aggregation footer double-counted expanded groups. Under row grouping it aggregated the *visible* rows: group rows, which already carry their subtotals in the same fields, plus the expanded leaves. Expanding a group inflated `sum`, and `count` / `avg` / `unique` were wrong even when every group was collapsed. The footer, `getAggregationResult()`, the `aggregationResult` / `rowCount` passed to `slots.footer`, and grouped-export grand totals now use the filtered data rows, independent of expansion.
197
+ - Group rows lost their label and expand toggle when the first column was hidden, and showed them mid-row when that column was reordered or another column was pinned left; the hierarchy UI now goes on the leftmost column on screen.
198
+ - Subtotals, the "(n)" count and `descendantCount` counted filtered-out rows; groups left empty by the filter are hidden.
199
+ - `getAggregationPosition` was ignored; it is now called for every group and once with `null` for the grand total.
200
+ - `groupingColDef` had no effect under tree data.
201
+ - `pinnedRows` disappeared under tree data and row grouping.
202
+ - Tree paths containing `/` collided with deeper paths.
203
+ - Grouping values `null` and `'null'`, `1` and `'1'` fell into the same group.
204
+ - Detail-panel callbacks ran for every rendered row, including group rows; they now run only for expanded data rows, and a throwing `getDetailPanelContent` is contained to its panel.
205
+ - A throwing `getDetailPanelHeight`, `groupingValueFormatter` or `getAggregationPosition` falls back to the default instead of crashing.
206
+ - `getGroupedExportRows` and `getAllFilteredRows` follow screen order when sorting by the hierarchy column.
207
+ - `defaultGroupingExpansionDepth` expands and loads lazy server tree nodes.
208
+
209
+ #### Aggregation & pivot
210
+
211
+ - Footer totals now use the column's `valueFormatter` for `sum` / `avg` / `min` / `max`; `count` / `unique` stay plain numbers, and date `min` / `max` show as dates.
212
+ - Group rows formatted counts with the column's currency or unit formatter.
213
+ - Blank cells, booleans and arrays counted as 0 in `sum` / `avg` / `min` / `max`; `count` / `unique` counted blank strings.
214
+ - Aggregates of `valueGetter` columns summed `row[field]` instead of the computed values.
215
+ - `aggregable: false` columns were aggregated when `aggregationModel` or `pivotModel` named them.
216
+ - Footer totals now come from the server whenever a `dataSource` drives the rows, including infinite scroll and server-only filtering.
217
+ - An inline `aggregationModel` refetched `getRows` and cleared server totals on every render; stale server totals no longer show under a new function, filter or sort, while pending, or after a failure.
218
+ - Pivot mode crashed with `RangeError` on datasets over ~110k rows with a `min` or `max` value field, and `count` counted numeric values only.
219
+ - Pivot: filters and the quick filter apply to source rows, filters on generated value columns apply to pivot rows, and the Grand Total matches the rows shown, stays last when sorting and is not selected by select-all.
220
+ - Pivot: `getRowId` collapsed the pivot into one row; `treeData` and `rowGroupingModel` crashed or regrouped it; a `dataSource` produced broken output (pivot is now ignored with a warning).
221
+ - Pivot: the same field twice (for example `sum` and `count`) doubled values; a source `valueFormatter` that reads row data crashed the grid.
222
+ - Pivot: row-label columns keep the source column's formatter, renderer, type and alignment; column-field headers are formatted; numeric column keys sort numerically.
223
+ - Pivot: an empty pivot keeps its value columns and shows the no-rows overlay; a row field named `id` no longer overwrites row ids; pivot rows no longer share ids with source rows.
224
+ - Pivot: leaving pivot mode restores the column order; a controlled `columnOrder` no longer puts value columns before the label column, and the Columns panel can reorder generated columns.
225
+ - Pivot: `getAggregationResult()` and `slots.footer` no longer report totals over pivot rows, and the Summaries panel no longer lists generated columns.
226
+ - PivotPanel: editing or removing one of two chips on the same field affected both; it now follows `aggregable: false`, `availableAggregationFunctions` and `groupable: false`, and its controls have descriptive names.
227
+
228
+ #### Layout & pinning
229
+
230
+ - Columns pinned out of column order overlapped or left gaps; header, body, footer and keyboard navigation now agree on `pinnedColumns` order.
231
+ - Column widths ignored `minWidth` / `maxWidth` for fixed, resized and pinned columns; percentage widths cascaded; pinned `%`, `flex` and `auto` columns were 100px wide.
232
+ - Top-pinned rows covered the header when column groups were used; the aggregation footer was hidden behind bottom-pinned rows.
233
+ - Keyboard navigation and `scrollToIndexes` left the target row under the footer or bottom-pinned rows; `scrollToIndexes({ colIndex })` left the column under system or right-pinned columns.
234
+ - `'auto'` detail panels are laid out at their real height; `getDetailPanelHeight` returning 0 renders 0px (was 200px).
235
+ - `onRowsScrollEnd` fired on every scroll event near the bottom (including horizontal scrolling) and never for a list shorter than the viewport; it now fires once per arrival, in grid and list view.
236
+ - The grid re-measures its viewport and restores the scroll position after list view is switched off.
237
+ - Infinite-scroll placeholder rows appeared before the last loaded row.
238
+ - Row-spanned cells painted over the sticky drag and expand columns.
239
+ - A new `overscanRowCount` applied only after scrolling.
240
+ - Pinned-section edge classes and shadows were not applied.
241
+ - `autoHeight` filtered visible rows in quadratic time.
242
+
243
+ #### Spanning & column groups
244
+
245
+ - Body cells lost `flex`, percentage and `auto` widths (misaligned with headers) as soon as any column used `colSpan`.
246
+ - `colSpan` / `rowSpan` recomputed on every resize tick (a ~2 s freeze per rows change at 100k rows) and cost time even when unused.
247
+ - Spans counted hidden columns, crossed into another pinned section, and crossed between pinned and scrolling rows.
248
+ - A span broke when its origin row or column scrolled out of the render window.
249
+ - Huge, Infinity, NaN or fractional span values hung or corrupted the grid; `aria-colspan` / `aria-rowspan` report the clamped value.
250
+ - A throwing `colSpan` / `rowSpan` callback unmounted the grid; it now falls back to no span with a dev warning. Infinite-scroll placeholder rows are never passed to span callbacks.
251
+ - `colSpan` received the raw field value instead of the `valueGetter` result, and a `colIndex` different from `renderCell`'s.
252
+ - `colSpan` plus `rowSpan` covered only the origin column in following rows.
253
+ - `rowSpan` painted over an expanded detail panel; a merged cell was capped by its origin column's `maxWidth`.
254
+ - Keyboard navigation lost focus on covered cells; arrows now cross a merged cell in one step.
255
+ - Column group header rows did not follow member columns under `flex` / `%` / `auto` widths, hiding, reordering and pinning; pinned groups scrolled away; non-contiguous groups caused duplicate-key errors.
256
+ - `GridColumnGroup.headerClassName` was ignored.
257
+ - Group header cells expose `aria-colspan` / `aria-colindex`, filler cells are hidden from assistive technology, and `aria-rowcount` counts group header rows.
258
+ - `rowSpan` never starts on or crosses group, subtotal, tree auto-parent or pivot Grand Total rows.
259
+
260
+ #### Column reorder & resize
261
+
262
+ - `onRowOrderChange` indices depended on page, sort, filter and pinned rows; rows with id `0` and columns with field `''` could not be reordered.
263
+ - With `rowReordering`, pinned rows had no handle cell and misaligned; pinned and group rows could be dragged and dropped onto.
264
+ - Row and column drags did not start in Firefox; drags from outside the grid were treated as reorders; a drag broke after its source row scrolled away.
265
+ - Header drag-reorder moved the wrong column after columns were added, when `__group__` appeared, or with a partial controlled `columnOrder`; dropping on a pinned column sent the dragged column to the far end.
266
+ - `pinnable: false` also blocked drag-reorder.
267
+ - Controlled or `initialState` `columnOrder` was ignored when `disableColumnReorder` was set.
268
+ - The Manage-columns panel listed columns in definition order, and its Reset did nothing under a controlled `columnOrder`.
269
+ - Resize clamped to a hidden 1000px maximum and snapped narrow columns to 50px; a click on the handle resized, sorted or turned a flex column fixed; ending a resize over the header sorted the column; right-pinned columns resized from the wrong edge; a resize kept running after unmount.
270
+ - `rowReordering` had no effect but showed handles in pivot mode.
271
+
272
+ #### Keyboard & accessibility
273
+
274
+ - Keys typed into inputs inside cells and detail panels were taken by the grid; clicking an input rendered by `renderCell` lost focus.
275
+ - Focus was lost when the focused cell scrolled out, on window switch, when tabbing out and back (the last cell is now restored), and when rows or columns were removed, filtered or hidden.
276
+ - Tab could not reach detail-panel content.
277
+ - Arrow keys stopped on hidden columns and ignored the pinned visual order; Space and arrows at the edges scrolled the viewport.
278
+ - ArrowDown onto a row with a tall detail panel scrolled the row out of view; Home onto an unpinned checkbox column did not scroll it into view.
279
+ - Enter / Space on the select-all header sorted by `__checkbox_col__` instead of selecting all.
280
+ - Keyboard sorting from a header ignored `multiSort` and Shift.
281
+ - Reorder, expand and checkbox columns were not real focus stops; pinned rows could not be edited.
282
+ - DOM focus did not return to the cell after a re-click or an edit.
283
+ - A row with id `"HEADER"` was treated as the header row.
284
+ - `aria-rowindex`, `aria-rowcount`, `aria-colindex`, `aria-colcount` and `aria-sort` were wrong; `colIndex` in `onCellClick`, `renderCell`, `cellClassName` and `renderHeader` was relative to the render window.
285
+ - The detail panel had an invalid row/gridcell structure.
286
+ - A cell whose `renderCell` threw stayed broken; it now recovers when the renderer or value changes.
287
+ - `GridTooltip` placement `left` / `right` did not work; it now opens on focus, uses `role="tooltip"` with `aria-describedby`, closes on Escape, uses theme colours and cleans up its timers.
288
+ - Columns-panel checkboxes are announced with their column name.
289
+
290
+ #### Clipboard
291
+
292
+ - Copy (Ctrl/Cmd+C and `apiRef.copySelectedRows()`) included hidden and `exportable: false` columns in definition order; it now copies the visible columns in screen order.
293
+ - Copy read `row[field]` instead of the `valueGetter` value before formatting.
294
+ - Values containing tabs, line breaks or quotes broke the pasted table; they are now quoted.
295
+ - Only selected rows on the current page and in expanded groups were copied; now every selected row that passes the filter is copied, including pinned rows and collapsed groups.
296
+ - Copying right after `selectRows` or from `onRowSelectionModelChange` copied the old selection.
297
+ - Focus moved to `<body>` after copying.
298
+ - Ctrl+C did not copy with Caps Lock on or with non-Latin keyboard layouts, and it copied while focus was outside the grid or a text selection was active.
299
+ - Fields starting with `__` (for example `__typename`) were not copied.
300
+ - The Ctrl+C listener was registered more than once.
301
+
302
+ #### Toolbar, header & list view
303
+
304
+ - `slots.toolbar` rejected `memo`, `forwardRef`, class and `lazy` components; switching the toolbar did not remount cleanly; an inline toolbar lost its state.
305
+ - `slotProps.toolbar` render props had implicitly-`any` parameters under `strict`; `slots.pagination` typed with `PaginationProps` did not type-check; `groupingColDef` required a `field`.
306
+ - The column menu offered Hide for `hideable: false` and pin actions for `pinnable: false` columns (including the grouping column).
307
+ - Manage columns worked only once (after the toolbar button or Escape closed the panel) and did nothing with a custom toolbar; it now opens a standalone panel. The Columns panel closes on Escape and `onColumnsPanelClose` fires on every close.
308
+ - The Summaries panel offered functions outside `availableAggregationFunctions` and omitted `unique`.
309
+ - Toolbar panels misaligned with a classic (non-overlay) scrollbar.
310
+ - List view passed loading placeholders to `renderCell`, paged incorrectly under tree data, ignored server totals, never fired `onRowsScrollEnd`, and gave `renderCell` no `value`, `formattedValue`, `colDef` or `rowMeta`; `aria-rowindex` restarted every page.
311
+ - List view ignored `loading`, `slots.loadingOverlay`, `slots.noRowsOverlay` and `slots.footer`, and showed "No Data" while loading; `listView` without `listViewColumn` rendered nothing (it now falls back to the grid with a dev warning).
312
+ - List view had no expand chevron or depth indent for tree-data and group parents.
313
+ - List view: `renderCell` errors are contained, group rows get no checkbox and fall back to their label, and "N items" counts data rows.
314
+ - Two column-menu hides or pins in the same tick both apply.
315
+
316
+ #### Theming
317
+
318
+ - `DataGridThemeProvider` left part of the palette to the OS colour scheme, so `darkTheme` in a light browser (or light presets in a dark browser) was unreadable.
319
+ - Brand presets and `colors.primary` did not recolour the toolbar, filter panel, column menu, selection and focus ring.
320
+ - `grid.rowHeight*` and `grid.headerHeight` did not size rows and the header (`compactTheme` now gives 36px rows and a 40px header).
321
+ - `toolbar.*`, `scrollbar.*`, `overlays.itemDanger*` and `grid.cellFocusBorder` had no effect.
322
+
323
+ #### Build & SSR
324
+
325
+ - **The package works on React 18 again.** The 2.1.0 build bundled React 19's JSX runtime, which React 18 cannot render (`recentlyCreatedOwnerStacks` error on first render). A build check now fails if the JSX runtime is bundled.
326
+ - `DataGrid` crashed under server rendering (`renderToString`, Next.js, Remix) because a panel read `document` during render.
327
+ - `docs/migration/` now ships in the npm package; the v2 → v3 guide was missing from `node_modules`.
328
+
329
+ #### Documentation
330
+
331
+ - The README, `llms.txt` and the AI context file no longer claim the stylesheet loads automatically: `import '@opencorestack/opengridx/styles'` is required.
332
+ - The README props tables list only real props, with correct defaults; `llms.txt` examples compile and use real APIs.
333
+ - Server-side guides describe the real requests; "millions of rows" is replaced by the browser's height limit (about 645k rows at 52px in Chromium).
334
+ - The theming docs no longer reference a non-existent `themes` export; the API reference and component pages were corrected against the code.
335
+
336
+ ### Performance
337
+
338
+ - Inline `columns` (a new array each render with the same definitions) no longer re-runs client filtering and sorting.
339
+ - The quick filter no longer re-reads every cell on each keystroke.
340
+ - Faster date formatting.
341
+
342
+ ### Added
343
+
344
+ - `GridColDef.valueSetter` (`GridValueSetterParams`) maps an edited value back onto the row for editable `valueGetter` columns.
345
+ - `renderEditCell` receives `onValueChange`, `onCommit` and `onCancel` (`GridRenderEditCellParams`); errors in custom editors are contained to their cell.
346
+ - `formattedValue` and `rowMeta` are passed to `renderEditCell` and to the function form of `cellClassName`, as they already were to `renderCell`.
347
+ - Default cell formatting by `GridColDef.type` when there is no `valueFormatter` (see *Breaking*).
348
+ - `GridFilterOperator` values `'='`, `'after'`, `'onOrAfter'`, `'before'` and `'onOrBefore'`; a date input and `singleSelect` / multi-select value controls in the filter panel; the panel notes conditions it cannot show.
349
+ - `onColumnOrderModelChange(columnOrder)` fires with the whole new order after every change, including the Columns panel's Reset.
350
+ - `disableClipboardCopy` prop; Ctrl+C events already handled (`defaultPrevented`) are left alone.
351
+ - Export options: `CsvExportOptions.escapeFormulas`, `CsvExportOptions.bom`, `ExcelExportOptions.escapeFormulas`, `PdfExportOptions.font` (a Unicode TrueType font), and `getRowId` on every export function.
352
+ - `GridGroupedExportRow.groupLabel`; `GridRowMeta.isGroupFooter` and the `ogx__row--group-footer` class for subtotal rows shown in `'footer'` position.
353
+ - Keyboard: Shift+Space selects the focused row, Ctrl/Cmd+A selects all, Alt+ArrowRight / Alt+ArrowLeft expand and collapse, Alt+ArrowDown or Ctrl+Enter opens the column menu, Alt+ArrowLeft / Alt+ArrowRight on a focused header resizes it (Shift for 50px steps).
354
+ - Enter on a non-editable cell: on a row with children (group rows, tree-data parents) it only toggles expansion, without firing `onRowClick` or selecting; on any other row it acts like a click (`onRowClick`, click-to-select).
355
+ - Keyboard navigation between rows in list view.
356
+ - Column resizing by touch and pen; resize separators expose `aria-valuenow` / `aria-valuemin` / `aria-valuemax`.
357
+ - `aria-level` / `aria-expanded` on hierarchy rows and `aria-multiselectable` on the grid.
358
+ - `GridTheme.mode` (`'light' | 'dark'`), `colors.white`, `colors.black`, `colors.gray` (50–900), `grid.cellFontSize` and `grid.headerFontSize`.
359
+ - Type exports: `GridRenderEditCellParams`, `GridValueSetterParams`, `GridThemeToolbar`, `GridThemeOverlays`, `GridThemeScrollbar`, `GridThemeSkeleton`, `GridThemeGrayScale`, `GridGroupedExportRow`, `GridRowScrollEndParams`, `GridColumnOrder`, `GridDataSourceState`, `GridDetailPanelHeight`, `GridAggregationPosition`, `GridSlots`, `GridSlotProps`, and the props types `CellProps`, `RowProps`, `HeaderProps`, `SkeletonProps`, `FilterPanelProps`, `PaginationProps`, `GridTooltipProps`, `ButtonProps`, `InputProps`, `CheckboxProps`.
360
+ - `Pagination` component export.
361
+ - Optional `rowId` prop on `Row`, and optional `ariaRowIndex` / `ariaColIndex` / `columnIndexMap` props on the exported `Row`, `Cell` and `Header` components.
362
+ - Optional props on the exported components: `Cell.isPinnedEdge` (adds the pinned-section edge class), `Cell.valueError` (shows a `valueGetter` error as a cell error), `Row.onDetailPanelHeightChange(rowId, height)` (measured height of an `'auto'` detail panel) and `Row.isCellEditable`.
363
+ - Dev warnings: the grid stylesheet is not loaded, `pinnedRows` ignored under hierarchy, content taller than browsers can scroll, duplicate row ids, empty or duplicate tree paths, `valueGetter` + `editable` without `valueSetter`, pivot combined with `dataSource` / tree data / row grouping, `listView` without `listViewColumn`.
364
+ - CSS hooks: `ogx__sticky-top`, `ogx__sticky-bottom`, `ogx__header-cell--pinned-left-last`, `ogx__header-cell--pinned-right-first`, `ogx__cell--pinned-left-last`, `ogx__cell--pinned-right-first`, `ogx__aggregation-spacer`, `ogx__aggregation-spacer--pinned`, `ogx__aggregation-footer--loading`, `ogx__loading-bar`, `ogx__loading-overlay--over-rows`, `ogx__loading-overlay--custom`, `ogx__cell-image`, `ogx-list-view__expand`, `ogx-list-view__loading`, `ogx-filter__hidden-note`, `ogx-filter__value-multiselect`, `ogx-col-group-cell--pinned`, `ogx-col-group-cell--pinned-left` / `--pinned-right`, `ogx-column-resize-handle--start`, `ogx-tooltip--left` / `--right`.
365
+
366
+ ### Changed
367
+
368
+ - Sorting is type- and language-aware (`Intl.Collator` with numeric collation, dates parsed, mixed kinds ordered by kind).
369
+ - The quick filter searches only visible, filterable columns, using `valueGetter` and `valueFormatter` text.
370
+ - Pinned columns render in `pinnedColumns.left` / `.right` order; the column menu appends, so the most recently pinned column sits next to the scrolling area.
371
+ - `onColumnOrderChange` indices are positions in the full current column order (including hidden columns and `__group__`).
372
+ - Header drag-reorder works inside a column group when `columnGroupingModel` is set (it was disabled for every column); the toolbar and Columns panel can no longer move a column out of its group.
373
+ - A synchronous `processRowUpdate` result is applied in the same event.
374
+ - `apiRef.current.copySelectedRows()` rejects when the clipboard write fails.
375
+ - `min` / `max` of dates return a `Date`; the default `avg` format in pivot cells is locale-grouped (`56,666.67`); the footer exposes `aria-busy` while server totals load.
376
+ - `GridToolbar` shows the Summaries button only when `onAggregationModelChange` is passed; toolbar triggers have `aria-haspopup="dialog"` and `aria-expanded`.
377
+ - `GridTooltip` renders into the theme provider (`.ogx-theme-provider`) with `position: fixed` instead of `document.body`.
378
+ - `useGridApiRef()` returns a `MutableRefObject<GridApi>` that is never `null` before mount; `GridInitialState` accepts partial `columns`.
379
+ - The exported `Header` reports a focused header cell as `focusedCell.id === null` (was `'HEADER'`).
380
+ - The exported `Cell` no longer stops propagation of the double-click that starts an edit, so it reaches the row (`onRowDoubleClick`).
381
+ - `onStateChange` fires on value changes only (it fired for every new prop identity). With `useGridStateStorage`, remount the grid with `<DataGrid key={storageKey}>` when the key changes; storage is read during the first render, so SSR apps with saved state should render the grid on the client only (see the migration guide, §26).
382
+ - `GridAggregationPosition` is `'inline' | 'footer' | null` (it was an unused `'footer' | 'inline' | 'both'`).
383
+ - Accent colours use CSS `color-mix()` (Chrome 111+, Safari 16.2+, Firefox 113+); `darkTheme` gives the toolbar a solid `#1e293b` background.
384
+
385
+ ### Typing changes
386
+
387
+ - Rows can be typed with your own interfaces and type aliases: every public generic is constrained by the new `GridValidRowModel` (`object`) instead of `GridRowModel`, and an untyped `GridColDef[]` can be passed next to typed rows. The README example now compiles under `strict`.
388
+ - `DataGrid` and the export functions, `usePivot` and `useAggregation` have a typed and an untyped-columns overload. Use `DataGridProps<R>` rather than `React.ComponentProps<typeof DataGrid>`.
389
+ - `GridColDef` row callbacks are declared as methods, so `GridColDef<Row>` is assignable to `GridColDef` when `Row` is a type alias or extends `GridRowModel`. For an interface without an index signature it is not: type the array as `GridColDef<Row>[]`, or leave the columns untyped and use the untyped-columns overload.
390
+ - Calling `col.renderEditCell(params)` yourself with a `GridRenderCellParams` is now a type error: its parameter is `GridRenderEditCellParams` (the old params plus `onValueChange`, `onCommit`, `onCancel`).
391
+ - `usePivot` is declared to return `PivotResult`; `UsePivotReturn` is now a type alias of it (same fields, no declaration merging).
392
+ - Exported `Header`: `focusedCell.id` is `GridRowId | null`. Exported `Cell`: `onEditStop(cancel?, field?)`. Exported `Row`: `onEditStop` params gain optional `id` / `field`; `rowSpanningCaches.hiddenCellOriginMap` is `Record<GridRowId, Record<string, GridRowId>>` (was `Record<number, Record<string, number>>`).
393
+ - Slots are typed with the props the grid passes: new `GridToolbarSlotProps`, `GridPaginationSlotProps`, `GridOverlaySlotProps`, `GridFooterSlotProps`. Known `slotProps` keys are type-checked.
394
+ - Export option types are generic (`CsvExportOptions<R>`, …), so `getRowId` receives your row type.
395
+ - New root exports: `GridValidRowModel`, `DataGridUntypedColumnsProps` and the slot props types.
396
+ - Removed unused, never-exported internal types (`GridEditCellProps`, `GridRowModes`, `GridRowModesModel`, `GridDetailPanelContent`, `GridDetailPanelState`, `GridVirtualizationState`, `GridRenderContext`, `GridAggregationFunction`).
397
+ - The repository is type-checked in CI (`npm run typecheck`: library, tests and demo).
398
+
399
+ ### Removed
400
+
401
+ - `GridThemeSkeleton.darkBaseColor` and `GridThemeSkeleton.darkHighlightColor` (they had no effect).
402
+ - The runtime underscore hierarchy fields on rows (see *Breaking*).
403
+ - The OS dark-mode (`prefers-color-scheme`) rules for the expand icon and detail panel; the theme palette colours them.
404
+
405
+ ---
406
+
8
407
  ## [2.1.0] — 2026-09-23
9
408
 
10
409
  Fixes from a consumer defect report (migration of an ERP report writer from ag-grid) plus issues found while verifying it.