@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.
- package/CHANGELOG.md +399 -0
- package/README.md +95 -72
- package/dist/index.d.ts +590 -131
- package/dist/opengridx.css +1 -1
- package/dist/opengridx.es.js +7891 -5631
- package/dist/opengridx.es.js.map +1 -1
- package/dist/opengridx.umd.js +17 -23
- package/dist/opengridx.umd.js.map +1 -1
- package/docs/API_REFERENCE.md +348 -166
- package/docs/README.md +6 -1
- package/docs/architecture/datagrid-orchestration.md +81 -0
- package/docs/architecture/grid-row-meta.md +102 -0
- package/docs/architecture/use-grid-columns.md +128 -0
- package/docs/architecture/use-grid-controlled-state.md +157 -0
- package/docs/architecture/use-grid-row-pipeline.md +120 -0
- package/docs/architecture/use-grid-scroll-sync.md +111 -0
- package/docs/architecture/use-grid-state-snapshot.md +90 -0
- package/docs/architecture/use-grid-virtualization.md +115 -0
- package/docs/architecture/use-grid-visible-rows.md +85 -0
- package/docs/assets/banner-alt.png +0 -0
- package/docs/assets/banner.png +0 -0
- package/docs/assets/hero.png +0 -0
- package/docs/assets/logo.png +0 -0
- package/docs/components/aggregation-footer.md +15 -10
- package/docs/components/cell.md +16 -6
- package/docs/components/column-group-header.md +55 -28
- package/docs/components/column-resize.md +17 -13
- package/docs/components/column-visibility.md +6 -7
- package/docs/components/datagrid.md +15 -13
- package/docs/components/empty-state.md +2 -1
- package/docs/components/error-overlay.md +12 -7
- package/docs/components/filter-panel.md +28 -8
- package/docs/components/header.md +28 -9
- package/docs/components/pagination.md +14 -8
- package/docs/components/row.md +21 -5
- package/docs/components/toolbar.md +27 -9
- package/docs/components/tooltip.md +16 -7
- package/docs/customization/slots-api.md +90 -38
- package/docs/customization/theming.md +66 -18
- package/docs/features/aggregation-pivot.md +75 -9
- package/docs/features/cell-spanning.md +80 -125
- package/docs/features/clipboard.md +41 -16
- package/docs/features/custom-pagination.md +38 -18
- package/docs/features/data-source.md +36 -13
- package/docs/features/editing-reordering.md +125 -16
- package/docs/features/export-guide.md +126 -39
- package/docs/features/filtering.md +44 -6
- package/docs/features/infinite-scroll.md +54 -46
- package/docs/features/keyboard-navigation.md +83 -0
- package/docs/features/list-view.md +58 -5
- package/docs/features/loading-states.md +18 -20
- package/docs/features/master-detail.md +18 -5
- package/docs/features/pdf-export.md +72 -19
- package/docs/features/pinning.md +24 -5
- package/docs/features/selection.md +50 -10
- package/docs/features/sorting-pagination.md +64 -14
- package/docs/features/state-persistence.md +78 -10
- package/docs/features/toolbar-customization.md +26 -17
- package/docs/features/tree-data-grouping.md +36 -8
- package/docs/features/virtualization.md +37 -14
- package/docs/migration/v1-to-v2.md +115 -0
- package/docs/migration/v2-to-v3.md +1233 -0
- package/docs/performance.md +124 -0
- package/docs/roadmap.md +5 -5
- package/lib/components/Cell/Cell.css +17 -1
- package/lib/components/Cell/Cell.tsx +129 -57
- package/lib/components/Cell/CellErrorBoundary.tsx +12 -6
- package/lib/components/Cell/GridEditInputCell.tsx +114 -41
- package/lib/components/ColumnGroupHeader/ColumnGroupHeader.css +7 -1
- package/lib/components/ColumnResizeHandle/ColumnResizeHandle.css +15 -2
- package/lib/components/ColumnResizeHandle/ColumnResizeHandle.tsx +104 -38
- package/lib/components/ColumnResizeHandle/clampResizeWidth.ts +13 -0
- package/lib/components/ColumnVisibilityPanel/ColumnVisibilityPanel.css +6 -0
- package/lib/components/ColumnVisibilityPanel/ColumnVisibilityPanel.tsx +21 -13
- package/lib/components/DataGrid/DataGrid.css +85 -12
- package/lib/components/DataGrid/DataGrid.tsx +582 -876
- package/lib/components/DataGrid/GridAggregationFooter.tsx +53 -17
- package/lib/components/DataGrid/GridErrorOverlay.tsx +15 -12
- package/lib/components/DataGrid/GridListView.tsx +165 -24
- package/lib/components/DataGrid/GridLiveRegion.tsx +31 -0
- package/lib/components/DataGrid/GridLoadingOverlay.tsx +27 -0
- package/lib/components/DataGrid/GridPaginationArea.tsx +44 -0
- package/lib/components/DataGrid/GridPinnedRows.tsx +62 -11
- package/lib/components/DataGrid/GridStandaloneColumnPanel.tsx +40 -38
- package/lib/components/DataGrid/GridToolbarSlot.tsx +51 -0
- package/lib/components/DataGrid/GridVirtualRows.tsx +40 -24
- package/lib/components/DetailPanel/DetailPanel.css +0 -6
- package/lib/components/DetailPanel/DetailPanel.tsx +34 -5
- package/lib/components/DetailPanel/DetailPanelContent.tsx +17 -0
- package/lib/components/FilterPanel/FilterPanel.css +13 -2
- package/lib/components/FilterPanel/FilterPanel.tsx +272 -99
- package/lib/components/Header/ColumnMenu.tsx +91 -39
- package/lib/components/Header/Header.css +6 -3
- package/lib/components/Header/Header.tsx +181 -160
- package/lib/components/ListView/ListView.css +25 -0
- package/lib/components/ListView/ListViewRow.tsx +76 -10
- package/lib/components/Pagination/Pagination.tsx +15 -7
- package/lib/components/Row/Row.tsx +177 -77
- package/lib/components/Toolbar/GlobalSearch.css +6 -3
- package/lib/components/Toolbar/GlobalSearch.tsx +26 -27
- package/lib/components/Toolbar/GridToolbar.css +12 -11
- package/lib/components/Toolbar/GridToolbar.tsx +133 -89
- package/lib/components/Toolbar/PivotPanel.tsx +89 -49
- package/lib/components/Tooltip/Tooltip.css +20 -0
- package/lib/components/Tooltip/Tooltip.tsx +68 -35
- package/lib/components/ui/Button.tsx +3 -0
- package/lib/components/ui/Checkbox.tsx +2 -1
- package/lib/components/ui/ExpandIcon.css +0 -9
- package/lib/components/ui/ExpandIcon.tsx +4 -1
- package/lib/hooks/core/gridApiPlaceholder.ts +34 -0
- package/lib/hooks/core/gridToolbarHostContext.ts +14 -0
- package/lib/hooks/core/useDataGrid.ts +115 -173
- package/lib/hooks/core/useGridAggregationApi.ts +72 -0
- package/lib/hooks/core/useGridApiMethods.ts +115 -0
- package/lib/hooks/core/useGridApiRef.ts +19 -4
- package/lib/hooks/core/useGridApiRefBinding.ts +18 -0
- package/lib/hooks/core/useGridAriaRows.ts +38 -0
- package/lib/hooks/core/useGridClipboardApi.ts +38 -0
- package/lib/hooks/core/useGridColumnLookup.ts +30 -0
- package/lib/hooks/core/useGridColumns.tsx +279 -76
- package/lib/hooks/core/useGridColumnsPanel.ts +77 -0
- package/lib/hooks/core/useGridControlledState.ts +99 -6
- package/lib/hooks/core/useGridDetailPanel.ts +51 -0
- package/lib/hooks/core/useGridDevWarnings.ts +104 -5
- package/lib/hooks/core/useGridFocusHandlers.ts +50 -0
- package/lib/hooks/core/useGridGroupingColumn.ts +62 -0
- package/lib/hooks/core/useGridHeaderHandlers.ts +92 -0
- package/lib/hooks/core/useGridHierarchy.ts +81 -0
- package/lib/hooks/core/useGridKeyboardNavigation.ts +447 -243
- package/lib/hooks/core/useGridLiveRowSelection.ts +67 -0
- package/lib/hooks/core/useGridPageCorrection.ts +55 -0
- package/lib/hooks/core/useGridRowIdOf.ts +32 -0
- package/lib/hooks/core/useGridRowInteractions.ts +81 -0
- package/lib/hooks/core/useGridRowPipeline.ts +69 -39
- package/lib/hooks/core/useGridRowSelection.ts +91 -0
- package/lib/hooks/core/useGridScrollSync.ts +80 -32
- package/lib/hooks/core/useGridScrollToIndexesApi.ts +45 -0
- package/lib/hooks/core/useGridStateSnapshot.ts +40 -5
- package/lib/hooks/core/useGridThemeDimensions.ts +49 -0
- package/lib/hooks/core/useGridToolbarProps.ts +97 -0
- package/lib/hooks/core/useGridViewport.ts +38 -0
- package/lib/hooks/core/useGridViewportSize.ts +26 -0
- package/lib/hooks/core/useGridVisibleRows.ts +17 -5
- package/lib/hooks/core/useLayout.ts +215 -195
- package/lib/hooks/core/useRowsScrollEndLatch.ts +41 -0
- package/lib/hooks/core/useStableColumns.ts +34 -0
- package/lib/hooks/features/useAggregation.ts +82 -51
- package/lib/hooks/features/useColumnGroupReorderGuard.ts +34 -0
- package/lib/hooks/features/useDetailPanelHeights.ts +29 -0
- package/lib/hooks/features/useGridClipboard.ts +133 -73
- package/lib/hooks/features/useGridDataSource.ts +354 -128
- package/lib/hooks/features/useGridEditing.ts +211 -51
- package/lib/hooks/features/useGridPivot.ts +92 -0
- package/lib/hooks/features/useGridSpanRenderWindow.ts +104 -0
- package/lib/hooks/features/useGridSpanning.ts +410 -306
- package/lib/hooks/features/usePivot.ts +0 -0
- package/lib/hooks/features/useServerTreeChildren.ts +50 -0
- package/lib/hooks/useColumnReorder.ts +38 -44
- package/lib/hooks/useRowGrouping.ts +298 -160
- package/lib/hooks/useRowReorder.ts +62 -31
- package/lib/hooks/useTreeData.ts +287 -220
- package/lib/index.ts +28 -2
- package/lib/state/index.ts +1 -0
- package/lib/state/types.ts +7 -1
- package/lib/state/useGridStateStorage.ts +88 -29
- package/lib/theme/DataGridThemeProvider.tsx +143 -38
- package/lib/theme/gridThemeContext.ts +5 -0
- package/lib/theme/index.ts +5 -0
- package/lib/theme/presets.ts +5 -4
- package/lib/theme/types.ts +40 -2
- package/lib/types/index.ts +313 -116
- package/lib/utils/aggregation/index.ts +119 -24
- package/lib/utils/aria/index.ts +40 -0
- package/lib/utils/columnGroups.ts +110 -0
- package/lib/utils/columnLookup.ts +33 -0
- package/lib/utils/columnWidth.ts +22 -0
- package/lib/utils/dataSource/index.ts +46 -0
- package/lib/utils/detailPanel.ts +66 -0
- package/lib/utils/dragData.ts +44 -0
- package/lib/utils/editing/index.ts +30 -0
- package/lib/utils/export/exportShared.ts +197 -0
- package/lib/utils/export/exportToExcelAdvanced.ts +278 -139
- package/lib/utils/export/exportToPdf.ts +143 -92
- package/lib/utils/export/groupLabel.ts +14 -0
- package/lib/utils/export/index.ts +278 -272
- package/lib/utils/export/pdfText.ts +50 -0
- package/lib/utils/filtering/index.ts +277 -148
- package/lib/utils/focus/index.ts +115 -0
- package/lib/utils/gridApiRows.ts +35 -0
- package/lib/utils/gridModes.ts +77 -0
- package/lib/utils/grouping/groupedExportRows.ts +91 -0
- package/lib/utils/pagination/index.ts +56 -0
- package/lib/utils/pinning/index.ts +77 -33
- package/lib/utils/pivot/index.ts +368 -0
- package/lib/utils/scroll/index.ts +55 -5
- package/lib/utils/scroll/scrollEnd.ts +18 -0
- package/lib/utils/sorting/index.ts +154 -30
- package/lib/utils/syntheticRows.ts +12 -0
- package/lib/utils/values.ts +206 -0
- package/lib/utils/viewport.ts +14 -0
- package/llms.txt +261 -164
- package/package.json +13 -5
- package/lib/components/ColumnGroupHeader/ColumnGroupHeader.tsx +0 -220
- package/lib/components/ColumnVisibilityPanel/ColumnVisibilityPanel.test.tsx +0 -85
- package/lib/components/DataGrid/DataGrid.defects.test.tsx +0 -103
- package/lib/components/DataGrid/DataGrid.regression.test.tsx +0 -132
- package/lib/components/DataGrid/DataGrid.smoke.test.tsx +0 -58
- package/lib/components/DataGrid/DataGrid.v2.test.tsx +0 -127
- package/lib/components/DataGrid/DataGrid.virtualization.browser.test.tsx +0 -183
- package/lib/components/Header/Header.test.tsx +0 -135
- package/lib/components/Pagination/Pagination.test.tsx +0 -64
- package/lib/hooks/core/useDataGrid.regression.test.ts +0 -66
- package/lib/hooks/core/useGridControlledState.test.ts +0 -86
- package/lib/hooks/core/useGridKeyboardNavigation.test.ts +0 -176
- package/lib/hooks/core/useGridRowPipeline.test.ts +0 -117
- package/lib/hooks/features/useAggregation.test.ts +0 -175
- package/lib/hooks/features/usePivot.test.ts +0 -202
- package/lib/hooks/useRowGrouping.test.ts +0 -298
- package/lib/hooks/useTreeData.test.ts +0 -83
- package/lib/utils/aggregation/aggregation.test.ts +0 -16
- package/lib/utils/export/exportToExcelAdvanced.test.ts +0 -109
- package/lib/utils/export/exportToPdf.test.ts +0 -120
- package/lib/utils/export/groupedExport.test.ts +0 -144
- package/lib/utils/filtering/filtering.test.ts +0 -178
- package/lib/utils/sorting/sorting.test.ts +0 -88
|
@@ -10,70 +10,42 @@ Cell spanning allows cells in the DataGrid to span across multiple columns (colu
|
|
|
10
10
|
- **Row Spanning**: Cells can span vertically across multiple rows
|
|
11
11
|
- **Dynamic Spanning**: Span values can be calculated dynamically based on cell data
|
|
12
12
|
- **Static Spanning**: Span values can be set as fixed numbers
|
|
13
|
-
- **Accessibility**: Automatic ARIA attributes (`aria-colspan`, `aria-rowspan`)
|
|
14
|
-
- **
|
|
13
|
+
- **Accessibility**: Automatic ARIA attributes (`aria-colspan`, `aria-rowspan`) and keyboard navigation that treats a merged area as one cell
|
|
14
|
+
- **Virtualization-aware**: A span stays rendered while any part of it is in view, horizontally and vertically
|
|
15
|
+
- **Zero cost when unused**: Nothing is computed unless a column declares `colSpan` or `rowSpan`
|
|
15
16
|
|
|
16
17
|
---
|
|
17
18
|
|
|
18
|
-
##
|
|
19
|
+
## How spans interact with other features
|
|
19
20
|
|
|
20
|
-
|
|
21
|
+
Spans are computed from the grid **as it is rendered**, so they follow the current column order, visibility, pinning, sorting, filtering and page:
|
|
21
22
|
|
|
22
|
-
|
|
23
|
+
| Feature | Behaviour |
|
|
24
|
+
| :--- | :--- |
|
|
25
|
+
| **Column visibility** | Hidden columns are skipped. `colSpan: 2` merges the origin with the next *visible* column, and the merged width and `aria-colspan` count visible columns only. |
|
|
26
|
+
| **Column order / reordering** | A span covers the columns that follow the origin in the current (rendered) order. |
|
|
27
|
+
| **Column pinning** | A span never crosses a pinned-section boundary: it is clamped to the end of the left-pinned, unpinned or right-pinned section its origin is in. |
|
|
28
|
+
| **Row pinning** | Spans are computed separately for the top-pinned rows, the scrolling rows and the bottom-pinned rows, and never reach from one into another. |
|
|
29
|
+
| **Sorting / filtering / pagination** | Spans are recomputed against the new row order, the filtered rows and the current page. `rowIndex` in the callback is the row's position in the rendered rows (top-pinned rows first). |
|
|
30
|
+
| **Master-detail** | A row span ends at a row whose detail panel is expanded, so the merged cell never covers the panel. |
|
|
31
|
+
| **Virtualization** | The render window is widened so a span is never cut: the row whose cell starts a visible row span, and the column that starts a visible column span, are always rendered. |
|
|
32
|
+
| **Column resizing, flex and percentage widths** | A merged cell is exactly as wide as the columns it covers, using their resolved widths. The origin column's own `minWidth` / `maxWidth` do not apply to the merged cell. Resizing never recomputes the spans. |
|
|
33
|
+
| **Keyboard navigation** | Arrow keys move over a merged area in one step and land on its origin cell; covered cells are never focused. While editing, Tab skips covered cells (outside edit mode Tab leaves the grid). |
|
|
34
|
+
| **Infinite scrolling** | The loading placeholder rows are never passed to `colSpan` / `rowSpan`. |
|
|
35
|
+
| **Row grouping, tree data, pivot** | Rows the grid made (group headers, subtotals, auto-created tree parents, the pivot Grand Total) are never a span origin, and a `rowSpan` ends before the next such row, so a span never merges data across a group boundary (v3.0+). |
|
|
23
36
|
|
|
24
|
-
|
|
25
|
-
- When rows are reordered by sorting, spanned cells may break visual continuity
|
|
26
|
-
- Subtotal/summary rows with spanning should remain in fixed positions
|
|
37
|
+
Spans on columns whose values change with sorting still work, but the merged areas move with the rows. For summary rows that must stay in place, disable sorting on the spanning column (`sortable: false`) or use [Row Pinning](./pinning.md).
|
|
27
38
|
|
|
28
|
-
|
|
29
|
-
- Hidden rows can cause spanned cells to appear disconnected or incomplete
|
|
30
|
-
- Filtering may hide parts of a spanned cell group
|
|
39
|
+
### Span values
|
|
31
40
|
|
|
32
|
-
|
|
33
|
-
- Moving columns can break the spanning logic
|
|
34
|
-
- Spanned cells depend on specific column order
|
|
41
|
+
The value returned (or set) for `colSpan` / `rowSpan` is normalised before it is used:
|
|
35
42
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
43
|
+
- Values larger than what is left are clamped: `colSpan` to the end of the origin's pinned section, `rowSpan` to the end of the row section (or to the first row with an expanded detail panel). `aria-colspan` / `aria-rowspan` show the clamped value.
|
|
44
|
+
- Fractions are rounded down (`1.7` → `1`).
|
|
45
|
+
- `Infinity` means "to the end" and is clamped like any other large value.
|
|
46
|
+
- `NaN`, `0`, negative numbers and non-numbers mean no span (`1`).
|
|
39
47
|
|
|
40
|
-
|
|
41
|
-
- Pinned columns with spanning can cause rendering conflicts
|
|
42
|
-
- Spanning across pinned and non-pinned columns is not supported
|
|
43
|
-
|
|
44
|
-
### Recommended Configuration
|
|
45
|
-
|
|
46
|
-
```tsx
|
|
47
|
-
const columns: GridColDef<Row>[] = [
|
|
48
|
-
{
|
|
49
|
-
field: 'summary',
|
|
50
|
-
headerName: 'Summary',
|
|
51
|
-
width: 200,
|
|
52
|
-
colSpan: (params) => params.row.isTotal ? 3 : 1,
|
|
53
|
-
// Disable conflicting features
|
|
54
|
-
sortable: false, // ✅ Disable sorting
|
|
55
|
-
hideable: false, // ✅ Disable column hiding
|
|
56
|
-
// Column reorder is disabled grid-wide via disableColumnReorder on <DataGrid>
|
|
57
|
-
// Note: Avoid pinning this column
|
|
58
|
-
renderCell: (params) => {
|
|
59
|
-
if (params.row.isTotal) {
|
|
60
|
-
return <strong>Total: {params.value}</strong>;
|
|
61
|
-
}
|
|
62
|
-
return params.value;
|
|
63
|
-
}
|
|
64
|
-
},
|
|
65
|
-
// Other columns...
|
|
66
|
-
];
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
### Why These Limitations Exist
|
|
70
|
-
|
|
71
|
-
Cell spanning fundamentally changes the grid's layout model:
|
|
72
|
-
- **Sorting/Filtering** change row order/visibility, breaking span relationships
|
|
73
|
-
- **Column operations** (reorder/hide/pin) modify the column structure that spans depend on
|
|
74
|
-
- **CSS Grid** requires stable column positions for proper spanning
|
|
75
|
-
|
|
76
|
-
**Best Practice**: Use cell spanning primarily for static summary rows, headers, or fixed layout sections where these features are not needed.
|
|
48
|
+
A `colSpan` or `rowSpan` function (or the `valueGetter` whose value it receives) that **throws** is treated as `1` for that cell, and a warning is logged in development. The rest of the grid keeps rendering.
|
|
77
49
|
|
|
78
50
|
---
|
|
79
51
|
|
|
@@ -127,7 +99,7 @@ const columns: GridColDef<Row>[] = [
|
|
|
127
99
|
if (params.row.isTotal) {
|
|
128
100
|
return <strong>Total: {params.row.name}</strong>;
|
|
129
101
|
}
|
|
130
|
-
return params.
|
|
102
|
+
return params.formattedValue;
|
|
131
103
|
}
|
|
132
104
|
},
|
|
133
105
|
{
|
|
@@ -145,7 +117,13 @@ const columns: GridColDef<Row>[] = [
|
|
|
145
117
|
### Basic Usage
|
|
146
118
|
|
|
147
119
|
```tsx
|
|
148
|
-
|
|
120
|
+
interface ItemRow {
|
|
121
|
+
id: number;
|
|
122
|
+
category: string;
|
|
123
|
+
item: string;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const columns: GridColDef<ItemRow>[] = [
|
|
149
127
|
{
|
|
150
128
|
field: 'category',
|
|
151
129
|
headerName: 'Category',
|
|
@@ -164,18 +142,18 @@ const columns: GridColDef<Row>[] = [
|
|
|
164
142
|
### Dynamic Row Spanning
|
|
165
143
|
|
|
166
144
|
```tsx
|
|
167
|
-
|
|
145
|
+
// `rows: ItemRow[]` is the array passed to the grid, sorted by category.
|
|
146
|
+
const columns: GridColDef<ItemRow>[] = [
|
|
168
147
|
{
|
|
169
148
|
field: 'category',
|
|
170
149
|
headerName: 'Category',
|
|
171
150
|
width: 150,
|
|
172
151
|
// Dynamic row span based on data
|
|
173
152
|
rowSpan: (params) => {
|
|
174
|
-
//
|
|
175
|
-
const
|
|
176
|
-
|
|
177
|
-
);
|
|
178
|
-
return categoryRows.length;
|
|
153
|
+
// Start a span at the first row of each category; the rest are covered by it
|
|
154
|
+
const index = rows.findIndex(r => r.category === params.row.category);
|
|
155
|
+
if (rows[index].id !== params.row.id) return 1;
|
|
156
|
+
return rows.filter(r => r.category === params.row.category).length;
|
|
179
157
|
}
|
|
180
158
|
},
|
|
181
159
|
{
|
|
@@ -190,10 +168,20 @@ const columns: GridColDef<Row>[] = [
|
|
|
190
168
|
|
|
191
169
|
## Combined Column and Row Spanning
|
|
192
170
|
|
|
193
|
-
You can use both `colSpan` and `rowSpan` together:
|
|
171
|
+
You can use both `colSpan` and `rowSpan` together. The origin cell then covers the whole rectangle: with `colSpan: 3` and `rowSpan: 2`, the three cells in the next row are covered too.
|
|
172
|
+
|
|
173
|
+
- A cell covered by another cell's `colSpan` is not evaluated as a `rowSpan` origin in that row.
|
|
174
|
+
- A cell covered by a `rowSpan` from above is not evaluated as a `colSpan` origin.
|
|
175
|
+
- A `colSpan` stops before a cell that a `rowSpan` from a row above already covers.
|
|
194
176
|
|
|
195
177
|
```tsx
|
|
196
|
-
|
|
178
|
+
interface SectionRow {
|
|
179
|
+
id: number;
|
|
180
|
+
header: string;
|
|
181
|
+
isHeader?: boolean;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const columns: GridColDef<SectionRow>[] = [
|
|
197
185
|
{
|
|
198
186
|
field: 'header',
|
|
199
187
|
headerName: 'Header',
|
|
@@ -209,11 +197,11 @@ const columns: GridColDef<Row>[] = [
|
|
|
209
197
|
textAlign: 'center',
|
|
210
198
|
padding: '20px'
|
|
211
199
|
}}>
|
|
212
|
-
{params.
|
|
200
|
+
{params.formattedValue}
|
|
213
201
|
</div>
|
|
214
202
|
);
|
|
215
203
|
}
|
|
216
|
-
return params.
|
|
204
|
+
return params.formattedValue;
|
|
217
205
|
}
|
|
218
206
|
}
|
|
219
207
|
];
|
|
@@ -292,7 +280,7 @@ export default function SalesReport() {
|
|
|
292
280
|
if (params.row.isSubtotal) {
|
|
293
281
|
return <em>{params.row.region} Subtotal</em>;
|
|
294
282
|
}
|
|
295
|
-
return params.
|
|
283
|
+
return params.formattedValue;
|
|
296
284
|
}
|
|
297
285
|
},
|
|
298
286
|
{
|
|
@@ -305,35 +293,35 @@ export default function SalesReport() {
|
|
|
305
293
|
headerName: 'Q1',
|
|
306
294
|
width: 120,
|
|
307
295
|
type: 'number',
|
|
308
|
-
valueFormatter: ({ value }) => `$${value.toLocaleString()}`
|
|
296
|
+
valueFormatter: ({ value }) => `$${(value as number).toLocaleString()}`
|
|
309
297
|
},
|
|
310
298
|
{
|
|
311
299
|
field: 'q2',
|
|
312
300
|
headerName: 'Q2',
|
|
313
301
|
width: 120,
|
|
314
302
|
type: 'number',
|
|
315
|
-
valueFormatter: ({ value }) => `$${value.toLocaleString()}`
|
|
303
|
+
valueFormatter: ({ value }) => `$${(value as number).toLocaleString()}`
|
|
316
304
|
},
|
|
317
305
|
{
|
|
318
306
|
field: 'q3',
|
|
319
307
|
headerName: 'Q3',
|
|
320
308
|
width: 120,
|
|
321
309
|
type: 'number',
|
|
322
|
-
valueFormatter: ({ value }) => `$${value.toLocaleString()}`
|
|
310
|
+
valueFormatter: ({ value }) => `$${(value as number).toLocaleString()}`
|
|
323
311
|
},
|
|
324
312
|
{
|
|
325
313
|
field: 'q4',
|
|
326
314
|
headerName: 'Q4',
|
|
327
315
|
width: 120,
|
|
328
316
|
type: 'number',
|
|
329
|
-
valueFormatter: ({ value }) => `$${value.toLocaleString()}`
|
|
317
|
+
valueFormatter: ({ value }) => `$${(value as number).toLocaleString()}`
|
|
330
318
|
},
|
|
331
319
|
{
|
|
332
320
|
field: 'total',
|
|
333
321
|
headerName: 'Total',
|
|
334
322
|
width: 140,
|
|
335
323
|
type: 'number',
|
|
336
|
-
valueFormatter: ({ value }) => value ? `$${value.toLocaleString()}`
|
|
324
|
+
valueFormatter: ({ value }) => (value == null ? '' : `$${(value as number).toLocaleString()}`)
|
|
337
325
|
}
|
|
338
326
|
];
|
|
339
327
|
|
|
@@ -387,7 +375,7 @@ Defines how many rows a cell should span.
|
|
|
387
375
|
rowSpan: 2
|
|
388
376
|
|
|
389
377
|
// Dynamic spanning
|
|
390
|
-
rowSpan: (params) => params.row.categorySize
|
|
378
|
+
rowSpan: (params) => (params.row.categorySize as number | undefined) ?? 1
|
|
391
379
|
```
|
|
392
380
|
|
|
393
381
|
### GridRenderCellParams
|
|
@@ -396,12 +384,14 @@ Parameters passed to the `colSpan` and `rowSpan` functions:
|
|
|
396
384
|
|
|
397
385
|
```tsx
|
|
398
386
|
interface GridRenderCellParams<R> {
|
|
399
|
-
value:
|
|
400
|
-
|
|
401
|
-
|
|
387
|
+
value: unknown; // Cell value: the valueGetter result when the column has one
|
|
388
|
+
formattedValue?: string; // The valueFormatter result (or String(value)); render this, not `value`
|
|
389
|
+
row: R; // Complete row data
|
|
390
|
+
field: string; // Column field name
|
|
402
391
|
colDef: GridColDef<R>; // Column definition
|
|
403
|
-
rowIndex: number;
|
|
404
|
-
colIndex: number;
|
|
392
|
+
rowIndex: number; // Position among the rendered rows (top-pinned rows, then the current page, then bottom-pinned rows)
|
|
393
|
+
colIndex: number; // Position among the rendered data columns (left-pinned first); checkbox, detail-panel and reorder columns are not counted
|
|
394
|
+
rowMeta?: GridRowMeta; // Hierarchy metadata under tree data / row grouping
|
|
405
395
|
}
|
|
406
396
|
```
|
|
407
397
|
|
|
@@ -430,11 +420,11 @@ Spanned cells can be styled using custom `renderCell`:
|
|
|
430
420
|
fontSize: '1.2em',
|
|
431
421
|
borderBottom: '2px solid #1976d2'
|
|
432
422
|
}}>
|
|
433
|
-
{params.
|
|
423
|
+
{params.formattedValue}
|
|
434
424
|
</div>
|
|
435
425
|
);
|
|
436
426
|
}
|
|
437
|
-
return params.
|
|
427
|
+
return params.formattedValue;
|
|
438
428
|
}
|
|
439
429
|
}
|
|
440
430
|
```
|
|
@@ -445,10 +435,10 @@ Spanned cells can be styled using custom `renderCell`:
|
|
|
445
435
|
|
|
446
436
|
The DataGrid automatically adds ARIA attributes for spanned cells:
|
|
447
437
|
|
|
448
|
-
- `aria-colspan`: Added when `colSpan > 1`
|
|
449
|
-
- `aria-rowspan`: Added when `rowSpan > 1`
|
|
438
|
+
- `aria-colspan`: Added when the (clamped) `colSpan > 1`
|
|
439
|
+
- `aria-rowspan`: Added when the (clamped) `rowSpan > 1`
|
|
450
440
|
|
|
451
|
-
|
|
441
|
+
Cells covered by a column span are not rendered. Cells covered by a row span render as empty `role="presentation"` placeholders that keep the column's slot. Keyboard focus always lands on the origin cell of a merged area.
|
|
452
442
|
|
|
453
443
|
---
|
|
454
444
|
|
|
@@ -456,43 +446,18 @@ This ensures screen readers properly announce the spanning behavior.
|
|
|
456
446
|
|
|
457
447
|
1. **Use Dynamic Spanning**: Prefer dynamic spanning functions over static values for flexibility
|
|
458
448
|
2. **Combine with renderCell**: Always provide custom rendering for spanned cells to improve visual clarity
|
|
459
|
-
3. **Consider Performance**:
|
|
460
|
-
4. **
|
|
449
|
+
3. **Consider Performance**: Span functions run once per cell of a spanning column whenever the rows or the column structure change (not on scroll or resize), so keep them lightweight
|
|
450
|
+
4. **Keep Row Spans Short**: While a long row span is on screen, every row from its origin down is rendered, so a 1,000-row span renders up to 1,000 rows
|
|
461
451
|
5. **Accessibility**: Provide meaningful content in spanned cells for screen readers
|
|
462
452
|
|
|
463
453
|
---
|
|
464
454
|
|
|
465
455
|
## Limitations
|
|
466
456
|
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
### Technical Limitations
|
|
472
|
-
|
|
473
|
-
1. **Virtualization**:
|
|
474
|
-
- Row spanning may have visual artifacts with virtualization if spans cross virtual boundaries
|
|
475
|
-
- Large row spans (>10 rows) may cause performance issues with virtual scrolling
|
|
476
|
-
- Consider using row pinning for summary rows instead of row spanning
|
|
477
|
-
|
|
478
|
-
2. **Pinned Columns**:
|
|
479
|
-
- Column spanning with pinned columns requires careful consideration
|
|
480
|
-
- Spanning across pinned and non-pinned columns is not supported
|
|
481
|
-
- Use spanning only within pinned or non-pinned column groups
|
|
482
|
-
|
|
483
|
-
3. **Sorting/Filtering**:
|
|
484
|
-
- Spanned cells may break visual continuity when rows are reordered
|
|
485
|
-
- Always disable sorting on columns with dynamic spanning
|
|
486
|
-
- Filtering can hide parts of spanned cell groups
|
|
487
|
-
|
|
488
|
-
4. **Column Operations**:
|
|
489
|
-
- Column reordering can break spanning logic
|
|
490
|
-
- Hiding columns within a span creates layout gaps
|
|
491
|
-
- Column resizing may not work optimally with spanned cells
|
|
492
|
-
|
|
493
|
-
5. **Editing**:
|
|
494
|
-
- Cell editing on spanned cells may have unexpected behavior
|
|
495
|
-
- Consider disabling editing for columns with spanning
|
|
457
|
+
1. **Pinned columns**: A span cannot cover columns in two pinned sections. Put the columns a span should merge in the same section.
|
|
458
|
+
2. **Pinned rows**: A span cannot reach from a pinned row into the scrolling rows (or the other way).
|
|
459
|
+
3. **Long row spans**: The rows between a visible row span's origin and the viewport are rendered, so very long row spans cost DOM nodes. Consider [Row Grouping](./tree-data-grouping.md) for large vertical groups.
|
|
460
|
+
4. **Editing**: Double-click editing on a merged cell edits the origin cell's field.
|
|
496
461
|
|
|
497
462
|
### Workarounds
|
|
498
463
|
|
|
@@ -502,19 +467,9 @@ This ensures screen readers properly announce the spanning behavior.
|
|
|
502
467
|
|
|
503
468
|
---
|
|
504
469
|
|
|
505
|
-
## Browser Support
|
|
506
|
-
|
|
507
|
-
Cell spanning uses CSS Grid, which is supported in:
|
|
508
|
-
- Chrome 57+
|
|
509
|
-
- Firefox 52+
|
|
510
|
-
- Safari 10.1+
|
|
511
|
-
- Edge 16+
|
|
512
|
-
|
|
513
|
-
---
|
|
514
|
-
|
|
515
470
|
## See Also
|
|
516
471
|
|
|
517
472
|
- [Row Pinning](./pinning.md)
|
|
518
473
|
- [Column Pinning](./pinning.md)
|
|
519
|
-
- [Custom Cell Rendering](
|
|
474
|
+
- [Custom Cell Rendering](../components/cell.md)
|
|
520
475
|
- [Aggregation](./aggregation-pivot.md)
|
|
@@ -4,9 +4,10 @@ OpenGridX supports copying grid data directly to the clipboard. This feature all
|
|
|
4
4
|
|
|
5
5
|
## 📑 Overview
|
|
6
6
|
- **Zero Configuration**: Enabled by default with the standard `DataGrid`.
|
|
7
|
-
- **Selected Rows**:
|
|
8
|
-
- **
|
|
9
|
-
- **
|
|
7
|
+
- **Selected Rows**: Every selected row that passes the filter is copied — rows on other pages, rows inside collapsed groups or tree nodes, and pinned rows included — in the order the grid shows them. Rows the filter removes are not copied.
|
|
8
|
+
- **What you see**: Only the visible columns are copied, in screen order (column order, drag reorder and pinning are followed). Columns marked `exportable: false` (action/button columns) are left out, as in every export.
|
|
9
|
+
- **TSV Format**: Data is copied in Tab-Separated Values (TSV) format, quoted the way Excel and Google Sheets read it.
|
|
10
|
+
- **Cell values**: `valueGetter` and then `valueFormatter` are applied, as in the cells.
|
|
10
11
|
|
|
11
12
|
---
|
|
12
13
|
|
|
@@ -16,7 +17,17 @@ Selection and copying follow standard spreadsheet metaphors:
|
|
|
16
17
|
| :--- | :--- |
|
|
17
18
|
| `Ctrl + C` / `Cmd + C` | Copy currently selected rows to the clipboard. |
|
|
18
19
|
|
|
19
|
-
> **Note**: The
|
|
20
|
+
> **Note**: The shortcut only copies while focus is inside the grid (a cell, a header, the toolbar), so with several grids on a page only the one in use copies, and Ctrl+C elsewhere on the page is never taken over (v3.0). It is also ignored while an input, textarea, or another editable element has focus, and while the page has a text selection, which the browser copies as usual. `apiRef.current.copySelectedRows()` is not affected by focus.
|
|
21
|
+
>
|
|
22
|
+
> The shortcut works with Caps Lock on and on non-Latin keyboard layouts (the key in the "C" position). Ctrl+Shift+C and Ctrl+Alt+C are not copy shortcuts and are left alone. Focus stays where it was after the copy.
|
|
23
|
+
|
|
24
|
+
### Taking over the shortcut
|
|
25
|
+
- Call `event.preventDefault()` in your own `keydown` handler (on the element, `document`, or in the capture phase) and the grid leaves that Ctrl+C alone.
|
|
26
|
+
- Or pass `disableClipboardCopy` to turn the grid's shortcut off entirely. `apiRef.current.copySelectedRows()` still works.
|
|
27
|
+
|
|
28
|
+
```tsx
|
|
29
|
+
<DataGrid rows={rows} columns={columns} disableClipboardCopy />
|
|
30
|
+
```
|
|
20
31
|
|
|
21
32
|
---
|
|
22
33
|
|
|
@@ -34,32 +45,46 @@ If `checkboxSelection` is enabled and rows are selected, pressing `Ctrl + C` wil
|
|
|
34
45
|
```
|
|
35
46
|
|
|
36
47
|
### Programmatic Copy
|
|
37
|
-
|
|
48
|
+
Call `apiRef.current.copySelectedRows()`, for example from a custom toolbar button. The promise resolves once the text is written (or straight away, writing nothing, when no selected row is found) and **rejects when the browser refuses the write**, so you can tell the user.
|
|
38
49
|
|
|
39
50
|
```tsx
|
|
40
|
-
import {
|
|
51
|
+
import { DataGrid, useGridApiRef } from '@opencorestack/opengridx';
|
|
41
52
|
|
|
42
|
-
function
|
|
43
|
-
const
|
|
53
|
+
function MyGrid({ rows, columns }) {
|
|
54
|
+
const apiRef = useGridApiRef();
|
|
55
|
+
|
|
56
|
+
const copy = async () => {
|
|
57
|
+
try {
|
|
58
|
+
await apiRef.current.copySelectedRows();
|
|
59
|
+
showToast('Copied');
|
|
60
|
+
} catch {
|
|
61
|
+
showToast('The browser blocked the clipboard');
|
|
62
|
+
}
|
|
63
|
+
};
|
|
44
64
|
|
|
45
65
|
return (
|
|
46
|
-
|
|
47
|
-
Copy to Clipboard
|
|
48
|
-
|
|
66
|
+
<>
|
|
67
|
+
<button onClick={copy}>Copy to Clipboard</button>
|
|
68
|
+
<DataGrid rows={rows} columns={columns} apiRef={apiRef} checkboxSelection />
|
|
69
|
+
</>
|
|
49
70
|
);
|
|
50
71
|
}
|
|
51
72
|
```
|
|
52
73
|
|
|
74
|
+
`copySelectedRows()` reads the latest selection, so it can be called right after `apiRef.current.selectRows(ids)` or from `onRowSelectionModelChange`.
|
|
75
|
+
|
|
53
76
|
---
|
|
54
77
|
|
|
55
78
|
## ⚙️ How it Works
|
|
56
79
|
|
|
57
|
-
1. **Header Row**: The first line of the copied content includes the column header names.
|
|
80
|
+
1. **Header Row**: The first line of the copied content includes the column header names (`headerName`, else `field`).
|
|
58
81
|
2. **Data Transformation**: The grid iterates through the selected rows and columns:
|
|
59
|
-
- **Exclusions**:
|
|
60
|
-
- **
|
|
61
|
-
3. **TSV Generation**: Fields are joined by tabs (`\t`), and rows are joined by newlines (`\n`).
|
|
62
|
-
4. **Clipboard API**: Uses
|
|
82
|
+
- **Exclusions**: Hidden columns, grid system columns (checkbox, expand, reorder, the `groupingColDef` column) and `exportable: false` columns are excluded. Synthetic group rows are never copied.
|
|
83
|
+
- **Values**: `valueGetter` runs first, then `valueFormatter` (also for empty values, as in the cells). Empty values are written as empty cells.
|
|
84
|
+
3. **TSV Generation**: Fields are joined by tabs (`\t`), and rows are joined by newlines (`\n`). A field that holds a tab, a line break or a double quote is wrapped in double quotes, with inner quotes doubled (`say "hi"` → `"say ""hi"""`), so the pasted table keeps its rows and columns.
|
|
85
|
+
4. **Clipboard API**: Uses `navigator.clipboard.writeText`. When it is missing (plain `http:` pages) or rejects, a hidden-textarea `document.execCommand('copy')` fallback runs; focus and the page selection are restored afterwards.
|
|
86
|
+
|
|
87
|
+
> **Formulas**: copy reproduces what the grid shows and does **not** neutralise formulas. A copied value that starts with `=`, `+`, `-` or `@` may be evaluated as a formula when pasted into Excel, Google Sheets or LibreOffice. The file exports (CSV, Excel, and the others) do neutralise such text by prefixing `'`; use an export when the data comes from untrusted input.
|
|
63
88
|
|
|
64
89
|
---
|
|
65
90
|
|
|
@@ -4,11 +4,22 @@ This guide shows how to use Ant Design (or any other UI library) components with
|
|
|
4
4
|
|
|
5
5
|
## Using Ant Design Select for Page Size
|
|
6
6
|
|
|
7
|
+
Slots are typed `React.ComponentType<Record<string, unknown>>`, so the component takes `Record<string, unknown>` and narrows it to the props it reads (see [Slots API](../customization/slots-api.md#available-slots)).
|
|
8
|
+
|
|
7
9
|
```tsx
|
|
8
|
-
import { Select } from 'antd';
|
|
10
|
+
import { Pagination, Select } from 'antd';
|
|
9
11
|
import { DataGrid } from '@opencorestack/opengridx';
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
type PaginationSlotProps = {
|
|
14
|
+
page: number;
|
|
15
|
+
pageSize: number;
|
|
16
|
+
rowCount: number;
|
|
17
|
+
pageSizeOptions: number[];
|
|
18
|
+
onPageChange: (page: number) => void;
|
|
19
|
+
onPageSizeChange: (pageSize: number) => void;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
function AntdPaginationComponent(props: Record<string, unknown>) {
|
|
12
23
|
const {
|
|
13
24
|
page,
|
|
14
25
|
pageSize,
|
|
@@ -16,12 +27,15 @@ function AntdPaginationComponent(props) {
|
|
|
16
27
|
pageSizeOptions,
|
|
17
28
|
onPageChange,
|
|
18
29
|
onPageSizeChange
|
|
19
|
-
} = props;
|
|
30
|
+
} = props as PaginationSlotProps;
|
|
20
31
|
|
|
21
|
-
|
|
22
|
-
const
|
|
23
|
-
const firstRowIndex = currentPage * pageSize;
|
|
32
|
+
// Client-side, `page` is already clamped to the last page.
|
|
33
|
+
const firstRowIndex = page * pageSize;
|
|
24
34
|
const lastRowIndex = Math.min(firstRowIndex + pageSize, rowCount);
|
|
35
|
+
// Show the page size in use even when it is not one of pageSizeOptions, as the built-in pager does.
|
|
36
|
+
const sizes = pageSizeOptions.includes(pageSize)
|
|
37
|
+
? pageSizeOptions
|
|
38
|
+
: [...pageSizeOptions, pageSize].sort((a, b) => a - b);
|
|
25
39
|
|
|
26
40
|
return (
|
|
27
41
|
<div style={{
|
|
@@ -38,7 +52,7 @@ function AntdPaginationComponent(props) {
|
|
|
38
52
|
<Select
|
|
39
53
|
value={pageSize}
|
|
40
54
|
onChange={onPageSizeChange}
|
|
41
|
-
options={
|
|
55
|
+
options={sizes.map(size => ({
|
|
42
56
|
value: size,
|
|
43
57
|
label: size
|
|
44
58
|
}))}
|
|
@@ -47,11 +61,11 @@ function AntdPaginationComponent(props) {
|
|
|
47
61
|
</div>
|
|
48
62
|
|
|
49
63
|
{/* Row count */}
|
|
50
|
-
<span>{firstRowIndex + 1}–{lastRowIndex} of {rowCount}</span>
|
|
64
|
+
<span>{rowCount === 0 ? 0 : firstRowIndex + 1}–{lastRowIndex} of {rowCount}</span>
|
|
51
65
|
|
|
52
66
|
{/* Ant Design Pagination */}
|
|
53
67
|
<Pagination
|
|
54
|
-
current={
|
|
68
|
+
current={page + 1}
|
|
55
69
|
total={rowCount}
|
|
56
70
|
pageSize={pageSize}
|
|
57
71
|
onChange={(page) => onPageChange(page - 1)}
|
|
@@ -86,15 +100,16 @@ function MyApp() {
|
|
|
86
100
|
|
|
87
101
|
```tsx
|
|
88
102
|
import { Select, MenuItem } from '@mui/material';
|
|
103
|
+
// PaginationSlotProps: the type alias from the example above
|
|
89
104
|
|
|
90
|
-
function MuiPaginationComponent(props) {
|
|
91
|
-
const { pageSize, pageSizeOptions, onPageSizeChange } = props;
|
|
105
|
+
function MuiPaginationComponent(props: Record<string, unknown>) {
|
|
106
|
+
const { pageSize, pageSizeOptions, onPageSizeChange } = props as PaginationSlotProps;
|
|
92
107
|
|
|
93
108
|
return (
|
|
94
109
|
<div>
|
|
95
110
|
<Select
|
|
96
111
|
value={pageSize}
|
|
97
|
-
onChange={(e) => onPageSizeChange(e.target.value)}
|
|
112
|
+
onChange={(e) => onPageSizeChange(Number(e.target.value))}
|
|
98
113
|
>
|
|
99
114
|
{pageSizeOptions.map(size => (
|
|
100
115
|
<MenuItem key={size} value={size}>
|
|
@@ -111,18 +126,23 @@ function MuiPaginationComponent(props) {
|
|
|
111
126
|
|
|
112
127
|
Your custom pagination component will receive these props:
|
|
113
128
|
|
|
114
|
-
- `page`: Current page index (0-based)
|
|
115
|
-
- `pageSize`: Current page size
|
|
116
|
-
- `rowCount`:
|
|
117
|
-
- `pageSizeOptions`: Array of available page sizes
|
|
129
|
+
- `page`: Current page index (0-based). With client pagination it is clamped to the last page: when the rows shrink below the current page, the grid shows the last page and reports the corrected page once through `onPaginationModelChange`.
|
|
130
|
+
- `pageSize`: Current page size. It may be a value missing from `pageSizeOptions` (the built-in pager then lists it as an extra option).
|
|
131
|
+
- `rowCount`: Number of rows being paged: the filtered, unpinned rows (pinned rows show on every page), or the server total with `paginationMode="server"`.
|
|
132
|
+
- `pageSizeOptions`: Array of available page sizes (default `[10, 25, 50, 100]`). The default page size is 100, or the first option when 100 is not offered.
|
|
118
133
|
- `onPageChange(newPage: number)`: Callback to change page
|
|
119
|
-
- `onPageSizeChange(newPageSize: number)`: Callback to change page size
|
|
134
|
+
- `onPageSizeChange(newPageSize: number)`: Callback to change page size (also goes back to page 0)
|
|
135
|
+
- `localeText`: `{ paginationRowsPerPage, paginationOf, paginationPage }`, passed only when the grid's `localeText` prop is set. The built-in pager uses `paginationRowsPerPage` as the select's label and accessible name.
|
|
120
136
|
- Any additional props from `slotProps.pagination`
|
|
121
137
|
|
|
138
|
+
The slot is rendered only while pagination is in effect: `pagination` is set, row grouping is off and `paginationMode` is not `"infinite"`. A `slots.footer` replaces it. List view uses it too.
|
|
139
|
+
|
|
122
140
|
## Other Customizable Slots
|
|
123
141
|
|
|
124
142
|
```tsx
|
|
125
143
|
<DataGrid
|
|
144
|
+
rows={rows}
|
|
145
|
+
columns={columns}
|
|
126
146
|
slots={{
|
|
127
147
|
pagination: CustomPaginationComponent,
|
|
128
148
|
noRowsOverlay: CustomNoRowsComponent,
|
|
@@ -140,4 +160,4 @@ Your custom pagination component will receive these props:
|
|
|
140
160
|
|
|
141
161
|
## Complete Example
|
|
142
162
|
|
|
143
|
-
See `demo/examples/CustomPagination.tsx` for a complete working example.
|
|
163
|
+
See `demo/examples/CustomPagination/CustomPagination.tsx` for a complete working example.
|