@mini_7/material-react-table-mcp 4.0.0
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/README.md +68 -0
- package/data/MIGRATION.md +136 -0
- package/data/api.json +5379 -0
- package/data/examples/advanced.tsx +309 -0
- package/data/examples/aggregation-and-grouping.tsx +153 -0
- package/data/examples/aggregation-multi.tsx +105 -0
- package/data/examples/alternate-column-filtering.tsx +49 -0
- package/data/examples/alternate-detail-panel.tsx +81 -0
- package/data/examples/alternate-pagination.tsx +23 -0
- package/data/examples/basic.tsx +109 -0
- package/data/examples/chart-detail-panel.tsx +89 -0
- package/data/examples/column-actions-space.tsx +44 -0
- package/data/examples/column-alignment.tsx +70 -0
- package/data/examples/custom-column-actions.tsx +109 -0
- package/data/examples/custom-column-filtering-ui.tsx +89 -0
- package/data/examples/custom-headless.tsx +125 -0
- package/data/examples/custom-top-toolbar.tsx +88 -0
- package/data/examples/customize-display-columns.tsx +85 -0
- package/data/examples/customize-filter-components.tsx +101 -0
- package/data/examples/customize-filter-modes.tsx +73 -0
- package/data/examples/customize-filter-variants.tsx +116 -0
- package/data/examples/customize-global-filter-component.tsx +52 -0
- package/data/examples/customize-remove-column-grouping.tsx +94 -0
- package/data/examples/customize-row-selection.tsx +54 -0
- package/data/examples/customize-table-styles.tsx +100 -0
- package/data/examples/disable-column-actions.tsx +37 -0
- package/data/examples/disable-column-hiding.tsx +90 -0
- package/data/examples/disable-density-toggle.tsx +49 -0
- package/data/examples/dynamic-columns.tsx +189 -0
- package/data/examples/editing-crud-cell.tsx +377 -0
- package/data/examples/editing-crud-modal.tsx +370 -0
- package/data/examples/editing-crud-row.tsx +333 -0
- package/data/examples/editing-crud-table.tsx +369 -0
- package/data/examples/editing-crud-tree.tsx +416 -0
- package/data/examples/enable-cell-actions.tsx +76 -0
- package/data/examples/enable-click-to-copy.tsx +39 -0
- package/data/examples/enable-column-grouping.tsx +120 -0
- package/data/examples/enable-column-ordering.tsx +48 -0
- package/data/examples/enable-column-pinning.tsx +69 -0
- package/data/examples/enable-column-resizing.tsx +56 -0
- package/data/examples/enable-column-virtualization.tsx +27 -0
- package/data/examples/enable-detail-panel-conditionally.tsx +78 -0
- package/data/examples/enable-detail-panel-virtualized.tsx +80 -0
- package/data/examples/enable-expanding-tree.tsx +110 -0
- package/data/examples/enable-filter-facet-values.tsx +65 -0
- package/data/examples/enable-row-dragging.tsx +137 -0
- package/data/examples/enable-row-numbers-original.tsx +48 -0
- package/data/examples/enable-row-numbers-static.tsx +48 -0
- package/data/examples/enable-row-ordering.tsx +57 -0
- package/data/examples/enable-row-pinning-select.tsx +76 -0
- package/data/examples/enable-row-pinning-static.tsx +50 -0
- package/data/examples/enable-row-pinning-sticky.tsx +69 -0
- package/data/examples/enable-row-selection.tsx +96 -0
- package/data/examples/enable-row-virtualization.tsx +101 -0
- package/data/examples/enable-sticky-header.tsx +59 -0
- package/data/examples/expanding-tree-expanded.tsx +121 -0
- package/data/examples/expanding-tree-flat-parse.tsx +125 -0
- package/data/examples/expanding-tree-root-expanded.tsx +151 -0
- package/data/examples/export-to-csv.tsx +114 -0
- package/data/examples/export-to-pdf.tsx +104 -0
- package/data/examples/external-toolbar.tsx +108 -0
- package/data/examples/font-awesome-icons.tsx +106 -0
- package/data/examples/infinite-scrolling.tsx +208 -0
- package/data/examples/lazy-detail-panel.tsx +262 -0
- package/data/examples/lazy-sub-rows.tsx +190 -0
- package/data/examples/linear-progress.tsx +66 -0
- package/data/examples/loading.tsx +50 -0
- package/data/examples/localization-i18n-ar.tsx +65 -0
- package/data/examples/localization-i18n-az.tsx +60 -0
- package/data/examples/localization-i18n-bg.tsx +60 -0
- package/data/examples/localization-i18n-cs.tsx +60 -0
- package/data/examples/localization-i18n-da.tsx +60 -0
- package/data/examples/localization-i18n-de.tsx +60 -0
- package/data/examples/localization-i18n-el.tsx +60 -0
- package/data/examples/localization-i18n-en.tsx +60 -0
- package/data/examples/localization-i18n-es.tsx +60 -0
- package/data/examples/localization-i18n-et.tsx +60 -0
- package/data/examples/localization-i18n-fa.tsx +66 -0
- package/data/examples/localization-i18n-fi.tsx +60 -0
- package/data/examples/localization-i18n-fr.tsx +60 -0
- package/data/examples/localization-i18n-he.tsx +66 -0
- package/data/examples/localization-i18n-hr.tsx +60 -0
- package/data/examples/localization-i18n-hu.tsx +60 -0
- package/data/examples/localization-i18n-hy.tsx +65 -0
- package/data/examples/localization-i18n-id.tsx +60 -0
- package/data/examples/localization-i18n-it.tsx +60 -0
- package/data/examples/localization-i18n-ja.tsx +60 -0
- package/data/examples/localization-i18n-ko.tsx +60 -0
- package/data/examples/localization-i18n-nl.tsx +60 -0
- package/data/examples/localization-i18n-no.tsx +60 -0
- package/data/examples/localization-i18n-np.tsx +60 -0
- package/data/examples/localization-i18n-pl.tsx +60 -0
- package/data/examples/localization-i18n-pt-BR.tsx +60 -0
- package/data/examples/localization-i18n-pt.tsx +60 -0
- package/data/examples/localization-i18n-ro.tsx +60 -0
- package/data/examples/localization-i18n-ru.tsx +60 -0
- package/data/examples/localization-i18n-sk.tsx +60 -0
- package/data/examples/localization-i18n-sr-Cyrl-RS.tsx +60 -0
- package/data/examples/localization-i18n-sr-Latn-RS.tsx +60 -0
- package/data/examples/localization-i18n-sv.tsx +60 -0
- package/data/examples/localization-i18n-tr.tsx +60 -0
- package/data/examples/localization-i18n-uk.tsx +60 -0
- package/data/examples/localization-i18n-vi.tsx +60 -0
- package/data/examples/localization-i18n-zh-hans.tsx +60 -0
- package/data/examples/localization-i18n-zh-hant.tsx +60 -0
- package/data/examples/manual-selection.tsx +105 -0
- package/data/examples/minimal.tsx +78 -0
- package/data/examples/mui-theme.tsx +136 -0
- package/data/examples/multi-sorting.tsx +58 -0
- package/data/examples/persistent-state.tsx +184 -0
- package/data/examples/react-query.tsx +182 -0
- package/data/examples/remote.tsx +150 -0
- package/data/examples/row-actions-buttons.tsx +89 -0
- package/data/examples/row-actions-menu-items.tsx +64 -0
- package/data/examples/single-row-selection.tsx +98 -0
- package/data/examples/virtualized.tsx +138 -0
- package/data/guides/accessibility.md +119 -0
- package/data/guides/aggregation.md +210 -0
- package/data/guides/async-loading.md +132 -0
- package/data/guides/best-practices.md +363 -0
- package/data/guides/cell-actions.md +139 -0
- package/data/guides/click-to-copy.md +67 -0
- package/data/guides/column-actions.md +69 -0
- package/data/guides/column-filtering.md +366 -0
- package/data/guides/column-grouping.md +192 -0
- package/data/guides/column-hiding.md +133 -0
- package/data/guides/column-ordering-dnd.md +99 -0
- package/data/guides/column-pinning.md +72 -0
- package/data/guides/column-resizing.md +157 -0
- package/data/guides/column-size.md +162 -0
- package/data/guides/customize-components.md +395 -0
- package/data/guides/customize-icons.md +35 -0
- package/data/guides/data-columns.md +292 -0
- package/data/guides/density-toggle.md +46 -0
- package/data/guides/detail-panel.md +195 -0
- package/data/guides/display-columns.md +135 -0
- package/data/guides/editing.md +367 -0
- package/data/guides/expanding-sub-rows.md +194 -0
- package/data/guides/full-screen-toggle.md +63 -0
- package/data/guides/global-filtering.md +237 -0
- package/data/guides/localization.md +57 -0
- package/data/guides/memoization.md +157 -0
- package/data/guides/pagination.md +171 -0
- package/data/guides/row-actions.md +116 -0
- package/data/guides/row-numbers.md +24 -0
- package/data/guides/row-ordering-dnd.md +51 -0
- package/data/guides/row-pinning.md +96 -0
- package/data/guides/row-selection.md +237 -0
- package/data/guides/sorting.md +190 -0
- package/data/guides/state-management.md +165 -0
- package/data/guides/sticky-header.md +41 -0
- package/data/guides/table-event-listeners.md +103 -0
- package/data/guides/toolbar-customization.md +251 -0
- package/data/guides/virtualization.md +183 -0
- package/data/index.json +1930 -0
- package/data/reference/mrt-components.md +183 -0
- package/data/reference/mrt-hooks.md +125 -0
- package/data/skills/composable-components/SKILL.md +189 -0
- package/data/skills/customization/SKILL.md +190 -0
- package/data/skills/drag-and-drop-ordering/SKILL.md +227 -0
- package/data/skills/editing/SKILL.md +243 -0
- package/data/skills/filtering/SKILL.md +213 -0
- package/data/skills/getting-started/SKILL.md +213 -0
- package/data/skills/localization/SKILL.md +182 -0
- package/data/skills/migrate-v3-to-v4/SKILL.md +161 -0
- package/data/skills/state-and-server-data/SKILL.md +200 -0
- package/data/skills/virtualization/SKILL.md +203 -0
- package/dist/data.js +137 -0
- package/dist/index.js +232 -0
- package/package.json +50 -0
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: drag-and-drop-ordering
|
|
3
|
+
description: >
|
|
4
|
+
Reorder columns and rows by drag and drop in Material React Table V4: enableColumnOrdering with the columnOrder state and mrt-row-* display column ids, enableRowOrdering with muiRowDragHandleProps onDragEnd reading draggingRow and hoveredRow, enableRowDragging for dropping rows onto other tables or UI, enableColumnDragging for column drags without reordering, and the draggingColumn, hoveredColumn, draggingRow, hoveredRow state. Load for user-arranged columns, sortable lists, moving rows between tables, or a drop that never fires.
|
|
5
|
+
metadata:
|
|
6
|
+
type: framework
|
|
7
|
+
library: '@mini_7/material-react-table'
|
|
8
|
+
library_version: '4.0.0'
|
|
9
|
+
framework: react
|
|
10
|
+
requires:
|
|
11
|
+
- getting-started
|
|
12
|
+
- state-and-server-data
|
|
13
|
+
- '@tanstack/table-core#column-ordering'
|
|
14
|
+
sources:
|
|
15
|
+
- 'gyminii/material-react-table:apps/material-react-table-docs/pages/docs/guides/column-ordering-dnd.mdx'
|
|
16
|
+
- 'gyminii/material-react-table:apps/material-react-table-docs/pages/docs/guides/row-ordering-dnd.mdx'
|
|
17
|
+
- 'gyminii/material-react-table:apps/material-react-table-docs/examples/enable-row-ordering/sandbox/src/TS.tsx'
|
|
18
|
+
- 'gyminii/material-react-table:apps/material-react-table-docs/examples/enable-row-dragging/sandbox/src/TS.tsx'
|
|
19
|
+
- 'gyminii/material-react-table:packages/material-react-table/src/components/body/MRT_TableBodyRowGrabHandle.tsx'
|
|
20
|
+
- 'gyminii/material-react-table:packages/material-react-table/src/utils/column.utils.ts'
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
This skill builds on `getting-started`, `state-and-server-data`, and `@tanstack/table-core#column-ordering`. MRT uses native HTML drag events with a grab handle button. Column ordering is fully built in; row ordering exposes the drag state and leaves the reorder of `data` to you.
|
|
24
|
+
|
|
25
|
+
## Setup
|
|
26
|
+
|
|
27
|
+
```tsx
|
|
28
|
+
const table = useMaterialReactTable({
|
|
29
|
+
columns,
|
|
30
|
+
data,
|
|
31
|
+
enableColumnOrdering: true, // drag handles in every header
|
|
32
|
+
enableRowOrdering: true, // adds the mrt-row-drag display column
|
|
33
|
+
enableSorting: false, // manual order and sorting fight each other
|
|
34
|
+
muiRowDragHandleProps: ({ table }) => ({
|
|
35
|
+
onDragEnd: () => {
|
|
36
|
+
const { draggingRow, hoveredRow } = table.getState()
|
|
37
|
+
if (draggingRow && hoveredRow) {
|
|
38
|
+
setData((old) => {
|
|
39
|
+
const next = [...old]
|
|
40
|
+
next.splice(hoveredRow.index!, 0, next.splice(draggingRow.index, 1)[0])
|
|
41
|
+
return next
|
|
42
|
+
})
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
}),
|
|
46
|
+
})
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Column-level `enableColumnOrdering: false` removes the handle from one column. `hoveredRow` and `hoveredColumn` are typed as partial objects because a drop target may be a placeholder; read `index` or `id` and guard for undefined.
|
|
50
|
+
|
|
51
|
+
## Core Patterns
|
|
52
|
+
|
|
53
|
+
### Set or persist the column order
|
|
54
|
+
|
|
55
|
+
```tsx
|
|
56
|
+
const [columnOrder, setColumnOrder] = useState<MRT_ColumnOrderState>([
|
|
57
|
+
'mrt-row-select',
|
|
58
|
+
'name',
|
|
59
|
+
'email',
|
|
60
|
+
'mrt-row-actions',
|
|
61
|
+
])
|
|
62
|
+
|
|
63
|
+
const table = useMaterialReactTable({
|
|
64
|
+
columns,
|
|
65
|
+
data,
|
|
66
|
+
enableRowSelection: true,
|
|
67
|
+
enableRowActions: true,
|
|
68
|
+
enableColumnOrdering: true,
|
|
69
|
+
state: { columnOrder },
|
|
70
|
+
onColumnOrderChange: setColumnOrder,
|
|
71
|
+
})
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
`columnOrder` is an array of column ids (`accessorKey` or `id`). Include the display column ids you enable (`mrt-row-select`, `mrt-row-actions`, `mrt-row-expand`, `mrt-row-numbers`, `mrt-row-drag`, `mrt-row-pin`) at the position you want; missing ones are appended at the start or end. If the array length does not match the column count MRT regenerates it, so `initialState.columnOrder` is enough when you only need a default. A dropped column is also pinned to the target column's pin position.
|
|
75
|
+
|
|
76
|
+
### Move rows between tables
|
|
77
|
+
|
|
78
|
+
```tsx
|
|
79
|
+
const [draggingRow, setDraggingRow] = useState<MRT_Row<Person> | null>(null)
|
|
80
|
+
const [hoveredTable, setHoveredTable] = useState<string | null>(null)
|
|
81
|
+
|
|
82
|
+
const common = {
|
|
83
|
+
columns,
|
|
84
|
+
enableRowDragging: true, // handle only; no in-table reorder
|
|
85
|
+
onDraggingRowChange: setDraggingRow,
|
|
86
|
+
state: { draggingRow },
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const table1 = useMaterialReactTable({
|
|
90
|
+
...common,
|
|
91
|
+
data: data1,
|
|
92
|
+
getRowId: (row) => `t1-${row.id}`,
|
|
93
|
+
muiRowDragHandleProps: {
|
|
94
|
+
onDragEnd: () => {
|
|
95
|
+
if (hoveredTable === 'table-2' && draggingRow) {
|
|
96
|
+
setData2((rows) => [...rows, draggingRow.original])
|
|
97
|
+
setData1((rows) => rows.filter((r) => r !== draggingRow.original))
|
|
98
|
+
}
|
|
99
|
+
setHoveredTable(null)
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
muiTablePaperProps: {
|
|
103
|
+
onDragEnter: () => setHoveredTable('table-1'),
|
|
104
|
+
sx: { outline: hoveredTable === 'table-1' ? '2px dashed' : undefined },
|
|
105
|
+
},
|
|
106
|
+
})
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
`enableRowDragging` shows the handle and maintains `draggingRow` without the in-table hover targets that `enableRowOrdering` adds. Any element can be a drop target through its own `onDragEnter`. Share `draggingRow` across tables by controlling it. Use `enableColumnDragging` the same way for columns that should be draggable onto external targets, for example a group-by drop zone.
|
|
110
|
+
|
|
111
|
+
### Style the drag interaction
|
|
112
|
+
|
|
113
|
+
```tsx
|
|
114
|
+
muiRowDragHandleProps: ({ row }) => ({
|
|
115
|
+
'aria-label': `Move ${row.original.name}`,
|
|
116
|
+
sx: { cursor: 'grab' },
|
|
117
|
+
}),
|
|
118
|
+
muiTableBodyRowProps: ({ row, table }) => ({
|
|
119
|
+
sx: {
|
|
120
|
+
opacity: table.getState().draggingRow?.id === row.id ? 0.5 : 1,
|
|
121
|
+
outline: table.getState().hoveredRow?.id === row.id ? '2px dashed' : undefined,
|
|
122
|
+
},
|
|
123
|
+
}),
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
`muiRowDragHandleProps` takes `IconButtonProps`; your `onDragStart` and `onDragEnd` run before MRT sets or clears `draggingRow`. `muiColumnDragHandleProps` is the column counterpart, and `hoveredColumn` / `draggingColumn` drive header styling. Replace the handle icon through `icons.DragHandleIcon`.
|
|
127
|
+
|
|
128
|
+
### Combine with virtualization
|
|
129
|
+
|
|
130
|
+
```tsx
|
|
131
|
+
enableRowOrdering: true,
|
|
132
|
+
enableRowVirtualization: true,
|
|
133
|
+
enablePagination: false,
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
The row virtualizer keeps the dragging row mounted while it is scrolled out of view, so drops still resolve. Keep `autoResetPageIndex: false` when paginated so a drop does not jump back to page one.
|
|
137
|
+
|
|
138
|
+
## Common Mistakes
|
|
139
|
+
|
|
140
|
+
### HIGH Reordering with the wrong row index
|
|
141
|
+
|
|
142
|
+
Wrong:
|
|
143
|
+
|
|
144
|
+
```tsx
|
|
145
|
+
onDragEnd: () => {
|
|
146
|
+
const { draggingRow, hoveredRow } = table.getState()
|
|
147
|
+
data.splice(hoveredRow.index, 0, data.splice(draggingRow.index, 1)[0])
|
|
148
|
+
setData(data) // same array reference, no re-render
|
|
149
|
+
},
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Correct:
|
|
153
|
+
|
|
154
|
+
```tsx
|
|
155
|
+
onDragEnd: () => {
|
|
156
|
+
const { draggingRow, hoveredRow } = table.getState()
|
|
157
|
+
if (!draggingRow || hoveredRow?.index === undefined) return
|
|
158
|
+
setData((old) => {
|
|
159
|
+
const next = [...old]
|
|
160
|
+
next.splice(hoveredRow.index!, 0, next.splice(draggingRow.index, 1)[0])
|
|
161
|
+
return next
|
|
162
|
+
})
|
|
163
|
+
},
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
`row.index` is the index in the original `data` array, so it is only meaningful when no client-side sort or filter is applied; and a mutated array with the same reference does not trigger a render.
|
|
167
|
+
|
|
168
|
+
Source: `docs/examples/enable-row-ordering`
|
|
169
|
+
|
|
170
|
+
### HIGH Expecting a drop callback
|
|
171
|
+
|
|
172
|
+
Wrong:
|
|
173
|
+
|
|
174
|
+
```tsx
|
|
175
|
+
onHoveredRowChange: (row) => moveRow(row), // fires on every hover, not on drop
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Correct:
|
|
179
|
+
|
|
180
|
+
```tsx
|
|
181
|
+
muiRowDragHandleProps: { onDragEnd: () => moveRow(table.getState().hoveredRow) },
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
There is no `onRowDrop`; the drop point is the handle's `onDragEnd`, after which MRT clears `draggingRow` and `hoveredRow`.
|
|
185
|
+
|
|
186
|
+
Source: `packages/material-react-table/src/components/body/MRT_TableBodyRowGrabHandle.tsx`
|
|
187
|
+
|
|
188
|
+
### MEDIUM Leaving sorting on with row ordering
|
|
189
|
+
|
|
190
|
+
Wrong:
|
|
191
|
+
|
|
192
|
+
```tsx
|
|
193
|
+
enableRowOrdering: true,
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Correct:
|
|
197
|
+
|
|
198
|
+
```tsx
|
|
199
|
+
enableRowOrdering: true,
|
|
200
|
+
enableSorting: false,
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
A sorted view re-sorts after every drop, so the user's arrangement disappears and `row.index` no longer maps to the visible position.
|
|
204
|
+
|
|
205
|
+
Source: `docs/guides/row-ordering-dnd.mdx`
|
|
206
|
+
|
|
207
|
+
### MEDIUM Column order array that ignores display columns
|
|
208
|
+
|
|
209
|
+
Wrong:
|
|
210
|
+
|
|
211
|
+
```tsx
|
|
212
|
+
initialState: { columnOrder: ['name', 'email'] }, // with enableRowSelection: true
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Correct:
|
|
216
|
+
|
|
217
|
+
```tsx
|
|
218
|
+
initialState: { columnOrder: ['mrt-row-select', 'name', 'email'] },
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
The length mismatch makes MRT regenerate the order from the column definitions, discarding the custom arrangement.
|
|
222
|
+
|
|
223
|
+
Source: `docs/guides/column-ordering-dnd.mdx`
|
|
224
|
+
|
|
225
|
+
## API Discovery
|
|
226
|
+
|
|
227
|
+
Search `node_modules/@mini_7/material-react-table/dist/index.d.ts` for `enableRowOrdering`, `enableRowDragging`, `muiRowDragHandleProps`, `muiColumnDragHandleProps`, `draggingRow`, and `hoveredColumn`. The Column Ordering and Row Ordering guides at `/docs/guides/column-ordering-dnd` and `/docs/guides/row-ordering-dnd` list the related options, and `/docs/examples/enable-column-ordering`, `enable-row-ordering`, and `enable-row-dragging` are runnable examples.
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: editing
|
|
3
|
+
description: >
|
|
4
|
+
Add create, update, and inline editing to Material React Table V4 with enableEditing, editDisplayMode (modal, row, cell, table, custom), createDisplayMode, onEditingRowSave and onCreatingRowSave with exitEditingMode, table.setEditingRow, table.setCreatingRow, muiEditTextFieldProps validation, editVariant select, and the Edit column slot. Load for CRUD tables, editable cells, row forms in a dialog, or when saved values never reach the callback.
|
|
5
|
+
metadata:
|
|
6
|
+
type: framework
|
|
7
|
+
library: '@mini_7/material-react-table'
|
|
8
|
+
library_version: '4.0.0'
|
|
9
|
+
framework: react
|
|
10
|
+
requires:
|
|
11
|
+
- getting-started
|
|
12
|
+
- customization
|
|
13
|
+
sources:
|
|
14
|
+
- 'gyminii/material-react-table:apps/material-react-table-docs/pages/docs/guides/editing.mdx'
|
|
15
|
+
- 'gyminii/material-react-table:apps/material-react-table-docs/examples/editing-crud-modal/sandbox/src/TS.tsx'
|
|
16
|
+
- 'gyminii/material-react-table:apps/material-react-table-docs/examples/editing-crud-cell/sandbox/src/TS.tsx'
|
|
17
|
+
- 'gyminii/material-react-table:packages/material-react-table/src/components/inputs/MRT_EditCellTextField.tsx'
|
|
18
|
+
- 'gyminii/material-react-table:packages/material-react-table/src/types.ts'
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
This skill builds on `getting-started` and `customization`. MRT renders the editing inputs and tracks which row or cell is being edited; persisting the values is always application code, wired through the save callbacks or the text field events.
|
|
22
|
+
|
|
23
|
+
## Setup
|
|
24
|
+
|
|
25
|
+
```tsx
|
|
26
|
+
const table = useMaterialReactTable({
|
|
27
|
+
columns,
|
|
28
|
+
data,
|
|
29
|
+
enableEditing: true,
|
|
30
|
+
editDisplayMode: 'modal', // default; also 'row' | 'cell' | 'table' | 'custom'
|
|
31
|
+
createDisplayMode: 'modal', // default; also 'row' | 'custom'
|
|
32
|
+
getRowId: (row) => row.id,
|
|
33
|
+
onEditingRowSave: async ({ values, table }) => {
|
|
34
|
+
await updateUser(values)
|
|
35
|
+
table.setEditingRow(null) // exit editing mode
|
|
36
|
+
},
|
|
37
|
+
onCreatingRowSave: async ({ values, table }) => {
|
|
38
|
+
await createUser(values)
|
|
39
|
+
table.setCreatingRow(null) // exit creating mode
|
|
40
|
+
},
|
|
41
|
+
renderRowActions: ({ row, table }) => (
|
|
42
|
+
<IconButton onClick={() => table.setEditingRow(row)}><EditIcon /></IconButton>
|
|
43
|
+
),
|
|
44
|
+
renderTopToolbarCustomActions: ({ table }) => (
|
|
45
|
+
<Button onClick={() => table.setCreatingRow(true)}>Create</Button>
|
|
46
|
+
),
|
|
47
|
+
})
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
`enableEditing` accepts a boolean or `(row) => boolean`, on the table and on each column. Column-level `enableEditing: false` renders a disabled field in the modal and the plain cell value in the other modes. The `editingRow`, `creatingRow`, and `editingCell` state slices hold the active row or cell; `table.setEditingRow`, `table.setCreatingRow`, and `table.setEditingCell` change them.
|
|
51
|
+
|
|
52
|
+
## Core Patterns
|
|
53
|
+
|
|
54
|
+
### Modal and row modes save through onEditingRowSave
|
|
55
|
+
|
|
56
|
+
```tsx
|
|
57
|
+
const handleSave: MRT_TableOptions<User>['onEditingRowSave'] = async ({ values, row, table, exitEditingMode }) => {
|
|
58
|
+
const errors = validateUser(values)
|
|
59
|
+
if (Object.values(errors).some(Boolean)) {
|
|
60
|
+
setValidationErrors(errors)
|
|
61
|
+
return // stay in editing mode
|
|
62
|
+
}
|
|
63
|
+
setValidationErrors({})
|
|
64
|
+
await updateUser({ ...row.original, ...values })
|
|
65
|
+
exitEditingMode() // same as table.setEditingRow(null)
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
`values` is a record keyed by column id, holding the edited text of every editable column. Nothing is written to `data`; the callback owns persistence. The callback may return a promise, and the `isSaving` state slice disables the save button and shows a spinner while it is true. `onEditingRowCancel` and `onCreatingRowCancel` fire when the user closes without saving, which is where validation errors get cleared.
|
|
70
|
+
|
|
71
|
+
### Cell and table modes save through the text field events
|
|
72
|
+
|
|
73
|
+
```tsx
|
|
74
|
+
const columns: MRT_ColumnDef<User>[] = [
|
|
75
|
+
{
|
|
76
|
+
accessorKey: 'email',
|
|
77
|
+
header: 'Email',
|
|
78
|
+
muiEditTextFieldProps: ({ cell, row }) => ({
|
|
79
|
+
type: 'email',
|
|
80
|
+
required: true,
|
|
81
|
+
error: !!validationErrors[cell.id],
|
|
82
|
+
helperText: validationErrors[cell.id],
|
|
83
|
+
onBlur: (event) => {
|
|
84
|
+
const value = event.currentTarget.value
|
|
85
|
+
setValidationErrors((prev) => ({ ...prev, [cell.id]: validateEmail(value) ? undefined : 'Invalid email' }))
|
|
86
|
+
setEditedUsers((prev) => ({ ...prev, [row.id]: { ...row.original, email: value } }))
|
|
87
|
+
},
|
|
88
|
+
}),
|
|
89
|
+
},
|
|
90
|
+
]
|
|
91
|
+
|
|
92
|
+
const table = useMaterialReactTable({
|
|
93
|
+
columns,
|
|
94
|
+
data,
|
|
95
|
+
enableEditing: true,
|
|
96
|
+
editDisplayMode: 'cell', // double-click a cell to edit it
|
|
97
|
+
})
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
In `'cell'` mode a double-click opens the field for that cell; in `'table'` mode every editable cell is a field at once. `onEditingRowSave` never fires in these modes. MRT calls your `onBlur` first, then stores the value in `row._valuesCache` and clears `editingCell`, so read `event.currentTarget.value` rather than `cell.getValue()`. Enter blurs the field. For single-click editing set `muiTableBodyCellProps` with an `onClick` that calls `table.setEditingCell(cell)` and focuses `table.refs.editInputRefs.current?.[column.id]`.
|
|
101
|
+
|
|
102
|
+
### Select inputs and custom Edit components
|
|
103
|
+
|
|
104
|
+
```tsx
|
|
105
|
+
{
|
|
106
|
+
accessorKey: 'state',
|
|
107
|
+
header: 'State',
|
|
108
|
+
editVariant: 'select',
|
|
109
|
+
editSelectOptions: usStates, // string[] or { label, value }[]
|
|
110
|
+
muiEditTextFieldProps: { select: true, required: true },
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
accessorKey: 'birthday',
|
|
114
|
+
header: 'Birthday',
|
|
115
|
+
Edit: ({ cell, column, row, table }) => (
|
|
116
|
+
<DatePicker
|
|
117
|
+
value={dayjs(cell.getValue<string>())}
|
|
118
|
+
onChange={(date) => {
|
|
119
|
+
row._valuesCache[column.id] = date?.toISOString()
|
|
120
|
+
if (table.getState().creatingRow?.id === row.id) table.setCreatingRow(row)
|
|
121
|
+
else table.setEditingRow(row)
|
|
122
|
+
}}
|
|
123
|
+
/>
|
|
124
|
+
),
|
|
125
|
+
},
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
`editSelectOptions` also accepts a callback receiving `cell`, `column`, `row`, and `table`. Select values save on change; text values save on blur. A custom `Edit` slot replaces the text field entirely, so it must write to `row._valuesCache[column.id]` and re-set the editing or creating row, otherwise the value never reaches `values` in the save callback.
|
|
129
|
+
|
|
130
|
+
### Customize the dialog and the create row
|
|
131
|
+
|
|
132
|
+
```tsx
|
|
133
|
+
import { MRT_EditActionButtons, createRow } from '@mini_7/material-react-table'
|
|
134
|
+
|
|
135
|
+
const table = useMaterialReactTable({
|
|
136
|
+
columns,
|
|
137
|
+
data,
|
|
138
|
+
enableEditing: true,
|
|
139
|
+
positionCreatingRow: 'bottom', // 'top' (default), 'bottom', or a row index
|
|
140
|
+
renderEditRowDialogContent: ({ internalEditComponents, row, table }) => (
|
|
141
|
+
<>
|
|
142
|
+
<DialogTitle>Edit user</DialogTitle>
|
|
143
|
+
<DialogContent sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>{internalEditComponents}</DialogContent>
|
|
144
|
+
<DialogActions><MRT_EditActionButtons table={table} row={row} variant="text" /></DialogActions>
|
|
145
|
+
</>
|
|
146
|
+
),
|
|
147
|
+
renderTopToolbarCustomActions: ({ table }) => (
|
|
148
|
+
<Button onClick={() => table.setCreatingRow(createRow(table, { id: crypto.randomUUID(), role: 'viewer' }))}>
|
|
149
|
+
Create with defaults
|
|
150
|
+
</Button>
|
|
151
|
+
),
|
|
152
|
+
})
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
`internalEditComponents` is the array of generated fields, one per column, so custom dialog content can reorder them or mix in other inputs. `renderCreateRowDialogContent` is the create counterpart. `table.setCreatingRow(true)` opens a blank row; `createRow(table, defaults)` seeds it. `muiEditRowDialogProps` reaches the Material UI `Dialog` itself. `editDisplayMode: 'custom'` and `createDisplayMode: 'custom'` keep the state slices and callbacks but render no MRT editing UI, for forms in a sidebar.
|
|
156
|
+
|
|
157
|
+
## Common Mistakes
|
|
158
|
+
|
|
159
|
+
### HIGH Forgetting to exit editing mode after saving
|
|
160
|
+
|
|
161
|
+
Wrong:
|
|
162
|
+
|
|
163
|
+
```tsx
|
|
164
|
+
onEditingRowSave: async ({ values }) => {
|
|
165
|
+
await updateUser(values)
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Correct:
|
|
170
|
+
|
|
171
|
+
```tsx
|
|
172
|
+
onEditingRowSave: async ({ values, table }) => {
|
|
173
|
+
await updateUser(values)
|
|
174
|
+
table.setEditingRow(null)
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
MRT does not close the dialog or row on its own, so validation can keep it open. Call `exitEditingMode()` or `table.setEditingRow(null)` once the save succeeds, and the create counterpart `table.setCreatingRow(null)`.
|
|
179
|
+
|
|
180
|
+
Source: `docs/guides/editing.mdx`
|
|
181
|
+
|
|
182
|
+
### HIGH Expecting the data array to update itself
|
|
183
|
+
|
|
184
|
+
Wrong:
|
|
185
|
+
|
|
186
|
+
```tsx
|
|
187
|
+
editDisplayMode: 'cell',
|
|
188
|
+
// no muiEditTextFieldProps handlers; edits vanish after blur
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Correct:
|
|
192
|
+
|
|
193
|
+
```tsx
|
|
194
|
+
muiEditTextFieldProps: ({ cell, row }) => ({
|
|
195
|
+
onBlur: (event) => saveCell(row.id, cell.column.id, event.currentTarget.value),
|
|
196
|
+
}),
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Edited text lives only in `row._valuesCache` until your code writes it to state or a server and the `data` prop changes.
|
|
200
|
+
|
|
201
|
+
Source: `packages/material-react-table/src/components/inputs/MRT_EditCellTextField.tsx`
|
|
202
|
+
|
|
203
|
+
### MEDIUM Passing removed Material UI text field props to the editor
|
|
204
|
+
|
|
205
|
+
Wrong:
|
|
206
|
+
|
|
207
|
+
```tsx
|
|
208
|
+
muiEditTextFieldProps: { InputProps: { startAdornment: <EuroIcon /> }, inputProps: { maxLength: 40 } }
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Correct:
|
|
212
|
+
|
|
213
|
+
```tsx
|
|
214
|
+
muiEditTextFieldProps: {
|
|
215
|
+
slotProps: { input: { startAdornment: <EuroIcon /> }, htmlInput: { maxLength: 40 } },
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Material UI V9 removed `InputProps` and `inputProps` from `TextField`; MRT merges `slotProps.input`, `slotProps.htmlInput`, and `slotProps.select` with its own.
|
|
220
|
+
|
|
221
|
+
Source: `MIGRATION.md`
|
|
222
|
+
|
|
223
|
+
### MEDIUM Editing without a stable row id
|
|
224
|
+
|
|
225
|
+
Wrong:
|
|
226
|
+
|
|
227
|
+
```tsx
|
|
228
|
+
useMaterialReactTable({ columns, data, enableEditing: true })
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
Correct:
|
|
232
|
+
|
|
233
|
+
```tsx
|
|
234
|
+
useMaterialReactTable({ columns, data, enableEditing: true, getRowId: (row) => row.id })
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Without `getRowId` rows are keyed by index, so `editingRow` and `creatingRow` can point at a different record after sorting, filtering, or an optimistic insert.
|
|
238
|
+
|
|
239
|
+
Source: `docs/examples/editing-crud-modal`
|
|
240
|
+
|
|
241
|
+
## API Discovery
|
|
242
|
+
|
|
243
|
+
Search `node_modules/@mini_7/material-react-table/dist/index.d.ts` for `editDisplayMode`, `onEditingRowSave`, `onCreatingRowSave`, `_valuesCache`, and `editInputRefs` to see the exact signatures. The Editing guide at `/docs/guides/editing` lists the related table, column, and state options, and `/docs/examples/editing-crud`, `editing-crud-row`, `editing-crud-cell`, `editing-crud-table`, and `editing-crud-tree` are complete TanStack Query CRUD examples.
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: filtering
|
|
3
|
+
description: >
|
|
4
|
+
Configure column and global filtering in Material React Table V4: filterVariant (text, select, multi-select, autocomplete, range, range-slider, checkbox, date, datetime, time and their ranges), enableFacetedValues, filterFn and filterFns, enableColumnFilterModes with columnFilterModeOptions, columnFilterDisplayMode, globalFilterFn and ranked results, filter match highlighting, and the muiFilter*Props. Load for dropdown or date filters, custom filter logic, filter mode menus, or search that matches the wrong rows.
|
|
5
|
+
metadata:
|
|
6
|
+
type: framework
|
|
7
|
+
library: '@mini_7/material-react-table'
|
|
8
|
+
library_version: '4.0.0'
|
|
9
|
+
framework: react
|
|
10
|
+
requires:
|
|
11
|
+
- getting-started
|
|
12
|
+
- '@tanstack/table-core#column-filtering'
|
|
13
|
+
- '@tanstack/table-core#global-filtering'
|
|
14
|
+
sources:
|
|
15
|
+
- 'gyminii/material-react-table:apps/material-react-table-docs/pages/docs/guides/column-filtering.mdx'
|
|
16
|
+
- 'gyminii/material-react-table:apps/material-react-table-docs/pages/docs/guides/global-filtering.mdx'
|
|
17
|
+
- 'gyminii/material-react-table:apps/material-react-table-docs/examples/customize-filter-variants/sandbox/src/TS.tsx'
|
|
18
|
+
- 'gyminii/material-react-table:packages/material-react-table/src/fns/filterFns.ts'
|
|
19
|
+
- 'gyminii/material-react-table:packages/material-react-table/src/utils/column.utils.ts'
|
|
20
|
+
- 'gyminii/material-react-table:packages/material-react-table/src/types.ts'
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
This skill builds on `getting-started`, `@tanstack/table-core#column-filtering`, and `@tanstack/table-core#global-filtering`. Client-side column filters and the global search are on by default. MRT adds filter inputs, filter variants, fuzzy matching, and filter mode menus on top of the TanStack filtering model; server-side filtering is covered by `state-and-server-data`.
|
|
24
|
+
|
|
25
|
+
## Setup
|
|
26
|
+
|
|
27
|
+
```tsx
|
|
28
|
+
const columns: MRT_ColumnDef<Person>[] = [
|
|
29
|
+
{ accessorKey: 'name', header: 'Name' }, // text filter, fuzzy
|
|
30
|
+
{ accessorKey: 'city', header: 'City', filterVariant: 'select' },
|
|
31
|
+
{ accessorKey: 'state', header: 'State', filterVariant: 'multi-select' },
|
|
32
|
+
{ accessorKey: 'salary', header: 'Salary', filterVariant: 'range-slider' },
|
|
33
|
+
{
|
|
34
|
+
accessorFn: (row) => new Date(row.hireDate), // filter and sort on a Date
|
|
35
|
+
id: 'hireDate',
|
|
36
|
+
header: 'Hired',
|
|
37
|
+
filterVariant: 'date-range',
|
|
38
|
+
Cell: ({ cell }) => cell.getValue<Date>().toLocaleDateString(),
|
|
39
|
+
},
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
const table = useMaterialReactTable({
|
|
43
|
+
columns,
|
|
44
|
+
data,
|
|
45
|
+
enableFacetedValues: true, // options and min/max come from the data
|
|
46
|
+
initialState: { showColumnFilters: true },
|
|
47
|
+
})
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
`enableColumnFilters` (table) and `enableColumnFilter` (column) turn column filters off; `enableGlobalFilter` does the same for search; `enableFilters: false` removes both. `showColumnFilters` and `showGlobalFilter` are state slices, so seed them in `initialState` to show the inputs immediately.
|
|
51
|
+
|
|
52
|
+
## Core Patterns
|
|
53
|
+
|
|
54
|
+
### Pick the variant and let it pick the filter function
|
|
55
|
+
|
|
56
|
+
```tsx
|
|
57
|
+
{ accessorKey: 'isActive', accessorFn: (row) => (row.isActive ? 'true' : 'false'), id: 'isActive', header: 'Active', filterVariant: 'checkbox' },
|
|
58
|
+
{ accessorKey: 'age', header: 'Age', filterVariant: 'range', filterFn: 'between' },
|
|
59
|
+
{ accessorKey: 'team', header: 'Team', filterVariant: 'autocomplete', filterSelectOptions: teams },
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Variants: `text` (default), `autocomplete`, `select`, `multi-select`, `range`, `range-slider`, `checkbox`, `date`, `date-range`, `datetime`, `datetime-range`, `time`, `time-range`. The default `filterFn` follows the variant: `multi-select` uses `arrIncludesSome`, any `range` variant uses `betweenInclusive`, `select` and `checkbox` use `equals`, everything else uses `fuzzy`. `filterSelectOptions` takes strings or `{ label, value }` objects; with `enableFacetedValues` the select, multi-select, autocomplete, and range-slider inputs fill themselves from the column's unique values or min and max. The checkbox variant compares against the strings `'true'` and `'false'`, so its accessor must return strings.
|
|
63
|
+
|
|
64
|
+
### Date, datetime, and time variants need the pickers provider
|
|
65
|
+
|
|
66
|
+
```tsx
|
|
67
|
+
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'
|
|
68
|
+
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'
|
|
69
|
+
|
|
70
|
+
<LocalizationProvider dateAdapter={AdapterDayjs}>
|
|
71
|
+
<MaterialReactTable table={table} />
|
|
72
|
+
</LocalizationProvider>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
MRT renders `@mui/x-date-pickers` V9 components for these variants and expects one `LocalizationProvider` above the table. The accessor should return a `Date` so comparisons and sorting work. `muiFilterDatePickerProps`, `muiFilterDateTimePickerProps`, and `muiFilterTimePickerProps` forward props to the picker; for range variants the callback form receives `rangeFilterIndex` (0 for the start input, 1 for the end).
|
|
76
|
+
|
|
77
|
+
### Custom filter functions
|
|
78
|
+
|
|
79
|
+
```tsx
|
|
80
|
+
const table = useMaterialReactTable({
|
|
81
|
+
columns: [
|
|
82
|
+
{ accessorKey: 'name', header: 'Name', filterFn: 'startsWith' }, // MRT built-in
|
|
83
|
+
{ accessorKey: 'code', header: 'Code', filterFn: 'includesStringSensitive' }, // TanStack built-in
|
|
84
|
+
{ accessorKey: 'tags', header: 'Tags', filterFn: 'hasAllTags' }, // registered below
|
|
85
|
+
],
|
|
86
|
+
data,
|
|
87
|
+
filterFns: {
|
|
88
|
+
hasAllTags: (row, columnId, filterValue: string) =>
|
|
89
|
+
filterValue.split(',').every((tag) => row.getValue<string[]>(columnId).includes(tag.trim())),
|
|
90
|
+
},
|
|
91
|
+
globalFilterFn: 'contains', // default is 'fuzzy'
|
|
92
|
+
})
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
MRT built-ins: `between`, `betweenInclusive`, `contains`, `empty`, `endsWith`, `equals`, `fuzzy`, `greaterThan`, `greaterThanOrEqualTo`, `lessThan`, `lessThanOrEqualTo`, `notEmpty`, `notEquals`, `startsWith`. TanStack built-ins such as `includesString`, `equalsString`, `arrIncludes`, `arrIncludesAll`, `arrIncludesSome`, `weakEquals`, and `inNumberRange` also work by name. A function passed to `filterFn` receives `(row, columnId, filterValue)` and returns a boolean; functions registered in `filterFns` become names usable in `filterFn`, `globalFilterFn`, and the filter mode menus. The `fuzzy` global filter ranks rows by match quality unless `enableGlobalFilterRankedResults` is false, a sort is active, rows are expanded, or a `manual*` option is set.
|
|
96
|
+
|
|
97
|
+
### Let users switch filter modes
|
|
98
|
+
|
|
99
|
+
```tsx
|
|
100
|
+
const table = useMaterialReactTable({
|
|
101
|
+
columns: [
|
|
102
|
+
{ accessorKey: 'name', header: 'Name', columnFilterModeOptions: ['fuzzy', 'contains', 'startsWith'] },
|
|
103
|
+
{ accessorKey: 'age', header: 'Age', columnFilterModeOptions: ['between', 'lessThan', 'greaterThan'] },
|
|
104
|
+
],
|
|
105
|
+
data,
|
|
106
|
+
enableColumnFilterModes: true,
|
|
107
|
+
enableGlobalFilterModes: true,
|
|
108
|
+
globalFilterModeOptions: ['fuzzy', 'startsWith'],
|
|
109
|
+
columnFilterDisplayMode: 'popover', // 'subheader' (default), 'popover', or 'custom'
|
|
110
|
+
})
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
The chosen modes live in the `columnFilterFns` and `globalFilterFn` state slices, controllable through `onColumnFilterFnsChange` and `onGlobalFilterFnChange`. `renderColumnFilterModeMenuItems` and `renderGlobalFilterModeMenuItems` replace the menu; each receives `onSelectFilterMode(name)` and `internalFilterOptions`. `columnFilterDisplayMode: 'custom'` keeps the filtering logic while you render inputs elsewhere with `column.setFilterValue`. Filter values arrive after a short debounce (200 ms client-side, 400 ms with `manualFiltering`).
|
|
114
|
+
|
|
115
|
+
### Keep match highlighting in custom cells
|
|
116
|
+
|
|
117
|
+
```tsx
|
|
118
|
+
{
|
|
119
|
+
accessorKey: 'name',
|
|
120
|
+
header: 'Name',
|
|
121
|
+
Cell: ({ renderedCellValue }) => <strong>{renderedCellValue}</strong>,
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Text filters and the global search highlight matches inside cells. A custom `Cell` keeps that only when it renders `renderedCellValue` instead of `cell.getValue()`. `enableFilterMatchHighlighting: false` turns it off per table or per column.
|
|
126
|
+
|
|
127
|
+
## Common Mistakes
|
|
128
|
+
|
|
129
|
+
### HIGH Filter variant does not match the accessor value type
|
|
130
|
+
|
|
131
|
+
Wrong:
|
|
132
|
+
|
|
133
|
+
```tsx
|
|
134
|
+
{ accessorKey: 'hireDate', header: 'Hired', filterVariant: 'date-range' } // hireDate is an ISO string
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Correct:
|
|
138
|
+
|
|
139
|
+
```tsx
|
|
140
|
+
{
|
|
141
|
+
accessorFn: (row) => new Date(row.hireDate),
|
|
142
|
+
id: 'hireDate',
|
|
143
|
+
header: 'Hired',
|
|
144
|
+
filterVariant: 'date-range',
|
|
145
|
+
Cell: ({ cell }) => cell.getValue<Date>().toLocaleDateString(),
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
The `betweenInclusive` comparison the date variants use works on `Date` objects and numbers, not on date strings, so string columns silently match everything or nothing.
|
|
150
|
+
|
|
151
|
+
Source: `docs/examples/customize-filter-variants`
|
|
152
|
+
|
|
153
|
+
### HIGH Reading the filter value with the wrong shape
|
|
154
|
+
|
|
155
|
+
Wrong:
|
|
156
|
+
|
|
157
|
+
```tsx
|
|
158
|
+
filterFn: (row, id, filterValue) => row.getValue<number>(id) >= filterValue, // range variant
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Correct:
|
|
162
|
+
|
|
163
|
+
```tsx
|
|
164
|
+
filterFn: (row, id, [min, max]: [number, number]) => {
|
|
165
|
+
const value = row.getValue<number>(id)
|
|
166
|
+
return (min === '' || value >= min) && (max === '' || value <= max)
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Range variants store `[min, max]` and multi-select stores an array; text, select, and checkbox store a single value. Match the shape or the custom function throws or filters everything out.
|
|
171
|
+
|
|
172
|
+
Source: `packages/material-react-table/src/fns/filterFns.ts`
|
|
173
|
+
|
|
174
|
+
### MEDIUM Passing removed Material UI text field props to filters
|
|
175
|
+
|
|
176
|
+
Wrong:
|
|
177
|
+
|
|
178
|
+
```tsx
|
|
179
|
+
muiFilterTextFieldProps: { InputProps: { startAdornment: <SearchIcon /> } }
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Correct:
|
|
183
|
+
|
|
184
|
+
```tsx
|
|
185
|
+
muiFilterTextFieldProps: { slotProps: { input: { startAdornment: <SearchIcon /> } } }
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Material UI V9 removed `InputProps` and `inputProps`; MRT merges `slotProps.input`, `slotProps.htmlInput`, and `slotProps.select` into its own.
|
|
189
|
+
|
|
190
|
+
Source: `MIGRATION.md`
|
|
191
|
+
|
|
192
|
+
### MEDIUM Mode menu offers a function that is not registered
|
|
193
|
+
|
|
194
|
+
Wrong:
|
|
195
|
+
|
|
196
|
+
```tsx
|
|
197
|
+
columnFilterModeOptions: ['fuzzy', 'isPrime'], // isPrime only exists in the column's filterFn
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Correct:
|
|
201
|
+
|
|
202
|
+
```tsx
|
|
203
|
+
filterFns: { isPrime: (row, id) => isPrime(row.getValue<number>(id)) },
|
|
204
|
+
columnFilterModeOptions: ['fuzzy', 'isPrime'],
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Filter mode names resolve through the table `filterFns` map. A name that is not there falls back to the default and the menu label shows the raw key.
|
|
208
|
+
|
|
209
|
+
Source: `docs/guides/column-filtering.mdx`
|
|
210
|
+
|
|
211
|
+
## API Discovery
|
|
212
|
+
|
|
213
|
+
Search `node_modules/@mini_7/material-react-table/dist/index.d.ts` for `filterVariant`, `MRT_FilterOption`, `filterFns`, and `muiFilter` for the exact unions and callback props. `MRT_FilterFns` is exported for reuse. The Column Filtering and Global Filtering guides at `/docs/guides/column-filtering` and `/docs/guides/global-filtering` list the related table, column, and state options, and `/docs/examples/customize-filter-variants`, `customize-filter-modes`, `enable-filter-facet-values`, and `alternate-column-filtering` are runnable examples.
|