react-gridix 0.2.0 → 0.2.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/README.md +306 -118
- package/dist/index.d.ts +36 -5
- package/dist/react-gridix.cjs +2 -2
- package/dist/react-gridix.js +1167 -918
- package/dist/style.css +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# react-gridix
|
|
1
|
+
# react-gridix
|
|
2
2
|
|
|
3
3
|
A React `DataGrid` with row selection, server-side mode, typed per-column filters, date columns, in-cell editing, resizing and pinning, virtualization, CSV export and 8 themes, plus the `Checkbox` it uses.
|
|
4
4
|
|
|
@@ -11,8 +11,9 @@ A React `DataGrid` with row selection, server-side mode, typed per-column filter
|
|
|
11
11
|
5. [Checkbox](#5-checkbox)
|
|
12
12
|
6. [DataGrid](#6-datagrid)
|
|
13
13
|
7. [Demos](#7-demos)
|
|
14
|
-
8. [
|
|
15
|
-
9. [
|
|
14
|
+
8. [Development, building and publishing](#8-development-building-and-publishing)
|
|
15
|
+
9. [Troubleshooting](#9-troubleshooting)
|
|
16
|
+
10. [Migrating from the earlier version](#10-migrating-from-the-earlier-version)
|
|
16
17
|
|
|
17
18
|
---
|
|
18
19
|
|
|
@@ -149,14 +150,14 @@ Pass a theme name to the grid. **Without a `theme` prop nothing changes**: the g
|
|
|
149
150
|
| --- | --- |
|
|
150
151
|
| `"ocean"` | Light, cool blues, blue gradient header, soft shadow |
|
|
151
152
|
| `"midnight"` | Dark slate, indigo accent, dark popups and inputs |
|
|
152
|
-
| `"sunset"` | Warm cream, orange-to-
|
|
153
|
+
| `"sunset"` | Warm cream, burnt-orange-to-raspberry gradient header, serif font, rounded corners |
|
|
153
154
|
| `"forest"` | Calm greens, solid dark-green header, sharper corners |
|
|
154
|
-
| `"lavender"` | Light purple,
|
|
155
|
+
| `"lavender"` | Light purple, deep violet gradient header, rounded corners |
|
|
155
156
|
| `"coffee"` | Warm browns and cream, serif font, rich brown header |
|
|
156
157
|
| `"graphite"` | Dark neutral grey with a teal accent, flat and sharp |
|
|
157
|
-
| `"aurora"` | Deep night blue with
|
|
158
|
+
| `"aurora"` | Deep night blue with an emerald-to-blue-to-violet gradient header and a soft glow |
|
|
158
159
|
|
|
159
|
-
A theme is only a set of CSS variables on `[data-
|
|
160
|
+
A theme is only a set of CSS variables on `[data-rg-theme="name"]`, written with `:where()` (zero specificity). So you can still override any variable or any class on top of a theme. Popups (the filter popup, the column menu) are drawn in `document.body`, and the grid copies the theme attribute onto them, so they follow the theme too.
|
|
160
161
|
|
|
161
162
|
**Switching themes at run time** is just a state change:
|
|
162
163
|
|
|
@@ -182,18 +183,18 @@ const dark = window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
|
182
183
|
|
|
183
184
|
```css
|
|
184
185
|
/* make the aurora header a single colour */
|
|
185
|
-
[data-
|
|
186
|
+
[data-rg-theme="aurora"] { --rg-header-bg: #0f766e; }
|
|
186
187
|
```
|
|
187
188
|
|
|
188
189
|
**Making your own theme.** Any other string works as a theme name. Define the variables you want:
|
|
189
190
|
|
|
190
191
|
```css
|
|
191
|
-
[data-
|
|
192
|
-
--
|
|
193
|
-
--
|
|
194
|
-
--
|
|
195
|
-
--
|
|
196
|
-
--
|
|
192
|
+
[data-rg-theme="brand"] {
|
|
193
|
+
--rg-header-bg: #7c3aed;
|
|
194
|
+
--rg-header-text: #fff;
|
|
195
|
+
--rg-row-hover: #f5f3ff;
|
|
196
|
+
--rg-selected-bg: #ede9fe; /* selected rows */
|
|
197
|
+
--rg-primary: #7c3aed;
|
|
197
198
|
}
|
|
198
199
|
```
|
|
199
200
|
|
|
@@ -201,7 +202,7 @@ const dark = window.matchMedia("(prefers-color-scheme: dark)").matches;
|
|
|
201
202
|
<DataGrid theme="brand" ... />
|
|
202
203
|
```
|
|
203
204
|
|
|
204
|
-
A dark custom theme should also set the colours that the light defaults assume, for example `--
|
|
205
|
+
A dark custom theme should also set the colours that the light defaults assume, for example `--rg-surface`, `--rg-text`, `--rg-border`, `--rg-pinned-bg`, `--rg-skeleton-a` and `--rg-skeleton-b`. Copy the `graphite` block in `themes.css` as a starting point.
|
|
205
206
|
|
|
206
207
|
### 4.2 CSS variables
|
|
207
208
|
|
|
@@ -209,59 +210,60 @@ Every variable is optional and is read with a fallback, so nothing is declared o
|
|
|
209
210
|
|
|
210
211
|
| Variable | Default | Used for |
|
|
211
212
|
| --- | --- | --- |
|
|
212
|
-
| `--
|
|
213
|
-
| `--
|
|
214
|
-
| `--
|
|
215
|
-
| `--
|
|
216
|
-
| `--
|
|
217
|
-
| `--
|
|
218
|
-
| `--
|
|
219
|
-
| `--
|
|
220
|
-
| `--
|
|
221
|
-
| `--
|
|
222
|
-
| `--
|
|
223
|
-
| `--
|
|
224
|
-
| `--
|
|
225
|
-
| `--
|
|
226
|
-
| `--
|
|
227
|
-
| `--
|
|
228
|
-
| `--
|
|
229
|
-
| `--
|
|
230
|
-
| `--
|
|
231
|
-
| `--
|
|
232
|
-
| `--
|
|
233
|
-
| `--
|
|
234
|
-
| `--
|
|
235
|
-
| `--
|
|
236
|
-
| `--
|
|
237
|
-
| `--
|
|
238
|
-
| `--
|
|
239
|
-
| `--
|
|
240
|
-
| `--
|
|
241
|
-
| `--
|
|
242
|
-
| `--
|
|
243
|
-
| `--
|
|
244
|
-
| `--
|
|
245
|
-
| `--
|
|
246
|
-
| `--
|
|
247
|
-
| `--
|
|
248
|
-
| `--
|
|
249
|
-
| `--
|
|
250
|
-
| `--
|
|
251
|
-
| `--
|
|
213
|
+
| `--rg-font` | system UI stack | Font family |
|
|
214
|
+
| `--rg-text` | `#111827` | Main text |
|
|
215
|
+
| `--rg-muted` | `#6b7280` | Secondary text, empty state |
|
|
216
|
+
| `--rg-border` | `#d1d5db` | Borders |
|
|
217
|
+
| `--rg-surface` | `#ffffff` | Background of the grid, inputs, buttons |
|
|
218
|
+
| `--rg-bg-subtle` | `#f3f4f6` | Header and footer background |
|
|
219
|
+
| `--rg-primary` | `#4f46e5` | Focus rings, active editor border |
|
|
220
|
+
| `--rg-danger` | `#dc2626` | Invalid editor border |
|
|
221
|
+
| `--rg-invalid-bg` | `#fef2f2` | Invalid editor background |
|
|
222
|
+
| `--rg-grid-bg` | `--rg-surface` | Grid background |
|
|
223
|
+
| `--rg-grid-radius` | `10px` | Grid corner radius |
|
|
224
|
+
| `--rg-grid-shadow` | `none` | Grid shadow |
|
|
225
|
+
| `--rg-toolbar-bg` | `transparent` | Toolbar background |
|
|
226
|
+
| `--rg-input-bg`, `--rg-input-border`, `--rg-input-text` | surface, border, inherit | Search box, filter inputs, editor, page controls |
|
|
227
|
+
| `--rg-header-bg` | `--rg-bg-subtle` | Header background. Any CSS background, so gradients work |
|
|
228
|
+
| `--rg-header-text` | inherit | Header text colour |
|
|
229
|
+
| `--rg-header-hover-bg` | `rgba(0,0,0,.06)` | Header hover |
|
|
230
|
+
| `--rg-header-border` | `--rg-border` | Line under the header |
|
|
231
|
+
| `--rg-cell-border` | `#eef0f3` | Lines between rows |
|
|
232
|
+
| `--rg-row-hover` | `#f3f4f6` | Row hover |
|
|
233
|
+
| `--rg-selected-bg` | `#eef2ff` | Background of selected rows |
|
|
234
|
+
| `--rg-on-primary` | `#ffffff` | Text colour on top of `--rg-primary` (the selected day in the calendar). Dark themes set a dark colour |
|
|
235
|
+
| `--rg-pinned-bg` | `--rg-grid-bg` | Opaque background behind pinned body cells (so scrolled cells do not show through) |
|
|
236
|
+
| `--rg-pinned-header-bg` | `--rg-bg-subtle` | Opaque background behind pinned header cells |
|
|
237
|
+
| `--rg-skeleton-a`, `--rg-skeleton-b` | `#e5e7eb`, `#f3f4f6` | The two colours of the shimmering loading bars |
|
|
238
|
+
| `--rg-stripe-a`, `--rg-stripe-b` | `transparent`, `#fafafa` | Alternating row colours (see [stripes](#striped-rows)) |
|
|
239
|
+
| `--rg-footer-bg`, `--rg-footer-text` | subtle, muted | Pagination bar |
|
|
240
|
+
| `--rg-btn-hover` | `#e5e7eb` | Page button, toolbar button and Clear button hover |
|
|
241
|
+
| `--rg-filter-active` | `--rg-primary` | Filter dot colour while a filter is set |
|
|
242
|
+
| `--rg-filter-glow` | `rgba(79,70,229,.25)` | Ring around an active filter dot |
|
|
243
|
+
| `--rg-popup-bg`, `--rg-popup-text`, `--rg-popup-border` | white, dark, grey | Filter popup and column menu |
|
|
244
|
+
| `--rg-popup-radius`, `--rg-popup-shadow` | `10px`, soft shadow | Popup shape |
|
|
245
|
+
| `--rg-row-duration` | `0.38s` | Row entrance animation length |
|
|
246
|
+
| `--rg-row-stagger` | `28ms` | Extra delay per row in the entrance animation |
|
|
247
|
+
| `--rg-checkbox-size` | `17px` | Checkbox width and height |
|
|
248
|
+
| `--rg-checkbox-border-width` | `1px` | Checkbox border width |
|
|
249
|
+
| `--rg-checkbox-radius` | `0` | Checkbox corner radius (square by default). The inner mark of the `"button"` variant is rounded half as much. The sunset and lavender themes use `2px` |
|
|
250
|
+
| `--rg-checkbox-color` | `#4f46e5` | Checked colour (also the focus ring and the native accent) |
|
|
251
|
+
| `--rg-checkbox-border` | `#9ca3af` | Border colour of an unchecked `"button"` / `"tick"` checkbox |
|
|
252
|
+
| `--rg-checkbox-bg` | `#ffffff` | Background of an unchecked `"button"` / `"tick"` checkbox |
|
|
253
|
+
| `--rg-checkbox-tick` | `#ffffff` | Colour of the tick, and of a custom character in the `"tick"` variant |
|
|
252
254
|
|
|
253
255
|
```css
|
|
254
256
|
:root {
|
|
255
|
-
--
|
|
256
|
-
--
|
|
257
|
-
--
|
|
257
|
+
--rg-primary: #0d9488;
|
|
258
|
+
--rg-row-hover: #f0fdfa;
|
|
259
|
+
--rg-selected-bg: #ccfbf1;
|
|
258
260
|
}
|
|
259
261
|
```
|
|
260
262
|
|
|
261
263
|
Scoped to one grid through its `style` prop:
|
|
262
264
|
|
|
263
265
|
```tsx
|
|
264
|
-
<DataGrid style={{ "--
|
|
266
|
+
<DataGrid style={{ "--rg-header-bg": "#0f172a", "--rg-header-text": "#fff" } as React.CSSProperties} ... />
|
|
265
267
|
```
|
|
266
268
|
|
|
267
269
|
---
|
|
@@ -315,16 +317,16 @@ A checkbox in three looks. Every variant toggles with **one click** (or the Spac
|
|
|
315
317
|
/>
|
|
316
318
|
```
|
|
317
319
|
|
|
318
|
-
(`aria-checked:` works for the `"button"` and `"tick"` variants. The native input has no `aria-checked`, so use the `--
|
|
319
|
-
2. **CSS variables**: `--
|
|
320
|
+
(`aria-checked:` works for the `"button"` and `"tick"` variants. The native input has no `aria-checked`, so use the `--rg-checkbox-color` variable for it.)
|
|
321
|
+
2. **CSS variables**: `--rg-checkbox-size`, `--rg-checkbox-border-width`, `--rg-checkbox-radius`, `--rg-checkbox-color`, `--rg-checkbox-border`, `--rg-checkbox-bg` and `--rg-checkbox-tick` (see [Theming](#42-css-variables)). Set them anywhere above the checkbox:
|
|
320
322
|
|
|
321
323
|
```tsx
|
|
322
|
-
<Checkbox styles={{ root: { "--
|
|
324
|
+
<Checkbox styles={{ root: { "--rg-checkbox-color": "#dc2626" } as CSSProperties }} ... />
|
|
323
325
|
```
|
|
324
|
-
3. **A custom character**, for example `indicator="★"` (any text, emoji or React node). It shows when the box is checked, in the `"button"` and `"tick"` variants. The default fill is dropped; the character is sized to the box (70% of `--
|
|
325
|
-
4. **Plain CSS** with these stable classes: `.
|
|
326
|
+
3. **A custom character**, for example `indicator="★"` (any text, emoji or React node). It shows when the box is checked, in the `"button"` and `"tick"` variants. The default fill is dropped; the character is sized to the box (70% of `--rg-checkbox-size`) and coloured with `--rg-checkbox-color` in the button variant and `--rg-checkbox-tick` in the tick variant. Restyle it through `classNames.indicator` / `styles.indicator`.
|
|
327
|
+
4. **Plain CSS** with these stable classes: `.rg-checkbox`, `.rg-checkbox--button`, `.rg-checkbox--tick`, `.rg-checkbox--native`, `.rg-checkbox--checked`, `.rg-checkbox--indeterminate`, `.rg-checkbox--disabled`, `.rg-checkbox__control`, `.rg-checkbox__indicator`, `.rg-checkbox__indicator--custom` and `.rg-checkbox__label`. State is also exposed as `data-state="checked"`, `"unchecked"` or `"indeterminate"` and, on the button variants, `aria-checked` (`"true"`, `"false"` or `"mixed"`).
|
|
326
328
|
|
|
327
|
-
**Defaults:** a 1px border and square corners (`--
|
|
329
|
+
**Defaults:** a 1px border and square corners (`--rg-checkbox-border-width: 1px`, `--rg-checkbox-radius: 0`). Round them with `--rg-checkbox-radius: 999px` or a Tailwind `rounded-*` class on `classNames.control`.
|
|
328
330
|
|
|
329
331
|
The checkbox CSS is written with `:where()` (zero specificity), so any class you add wins without `!important`.
|
|
330
332
|
|
|
@@ -332,6 +334,8 @@ The checkbox CSS is written with `:where()` (zero specificity), so any class you
|
|
|
332
334
|
|
|
333
335
|
---
|
|
334
336
|
|
|
337
|
+
---
|
|
338
|
+
|
|
335
339
|
## 6. DataGrid
|
|
336
340
|
|
|
337
341
|
### 6.1 Concepts
|
|
@@ -406,7 +410,8 @@ The grid is generic: `DataGrid<T>` infers `T` from `rows`, and `ColumnDef<T>` ch
|
|
|
406
410
|
| `serverSide` | `boolean` | `false` | Your server sorts, filters, searches and pages |
|
|
407
411
|
| `rowCount` | `number` | | Total rows on the server (for the page count) |
|
|
408
412
|
| `onQueryChange` | `(query: GridQuery) => void \| Promise<unknown>` | | Called on mount and whenever the query changes. A returned promise drives the loading state |
|
|
409
|
-
| `queryDebounce` | `number` | `250` | Milliseconds to wait after the last keystroke before querying |
|
|
413
|
+
| `queryDebounce` | `number` | `250` | Milliseconds to wait after the last keystroke in the search box before querying |
|
|
414
|
+
| `filterDebounce` | `number` | `300` | Milliseconds to wait after the last keystroke in a typed column filter (text, exact, number) before it is applied. A column can override it. See [Debouncing typed filters](#debouncing-typed-filters) |
|
|
410
415
|
| `loading` | `boolean` | follows the promise | Force the loading state on or off |
|
|
411
416
|
| `loadingRows` | `number` | page size (max 20), or 5 | How many skeleton rows to draw |
|
|
412
417
|
| `skeletonRow` | `ComponentType<SkeletonRowProps<T>>` | shimmer bars | Your own component for each placeholder row |
|
|
@@ -435,6 +440,7 @@ The grid is generic: `DataGrid<T>` infers `T` from `rows`, and `ColumnDef<T>` ch
|
|
|
435
440
|
| `striped` | `boolean` | `false` | Alternate row shading |
|
|
436
441
|
| `stripeColors` | `[string, string]` | | Two colours for the alternating rows. Implies `striped`. See [striped rows](#striped-rows) |
|
|
437
442
|
| `animateRows` | `boolean` | `true` | Rows slide up and fade in when they render. See [row animation](#row-animation) |
|
|
443
|
+
| `rowAnimationClassName` | `string \| (row, rowIndex) => string` | | Your own CSS class for the entrance animation. Replaces the built-in slide-up. See [custom row animation](#custom-row-animation) |
|
|
438
444
|
| `checkboxVariant` | `"button" \| "tick" \| "native"` | `"native"` | Checkbox look for boolean columns and row selection. Columns can override it |
|
|
439
445
|
| `maxHeight` | `number \| string` | | Makes the body scroll, with a sticky header. Example: `400` or `"60vh"` |
|
|
440
446
|
| `className` | `string` | | Classes for the root element (Tailwind works). The grid is `width: 100%` of its container by default |
|
|
@@ -458,7 +464,9 @@ const columns: ColumnDef<Employee>[] = [
|
|
|
458
464
|
| --- | --- | --- |
|
|
459
465
|
| `field` | `FieldPath<T>` | **Required.** Key of the row object this column reads and writes. Use dot notation for nested objects: `"contact.phone"` |
|
|
460
466
|
| `headerName` | `string` | Header text. Defaults to the field name, except in `type: "boolean"` columns, where it defaults to an empty string |
|
|
461
|
-
| `type` | `"text" \| "number" \| "boolean" \| "date"` | `"number"` columns edit and parse as numbers, `"boolean"` columns show a checkbox, `"date"` columns have a
|
|
467
|
+
| `type` | `"text" \| "number" \| "boolean" \| "date" \| "sequence"` | `"number"` columns edit and parse as numbers, `"boolean"` columns show a checkbox, `"date"` columns have a calendar picker (see [6.6](#66-date-columns)), `"sequence"` columns show row numbers (see [row numbers](#row-numbers-sequence-column)). Default `"text"` |
|
|
468
|
+
| `sequenceStart` | `number` | Only for `type: "sequence"`: the number of the first row (default `1`) |
|
|
469
|
+
| `sequenceRestartEachPage` | `boolean` | Only for `type: "sequence"`: start again at `sequenceStart` on every page (default `false`: the count continues, 11, 12, ...) |
|
|
462
470
|
| `width` | `number \| string` | Header cell width |
|
|
463
471
|
| `minWidth` / `maxWidth` | `number \| string` / `number` | Smallest and largest width (`maxWidth` limits dragging when resizing) |
|
|
464
472
|
| `align` | `"left" \| "center" \| "right"` | Text alignment for the header, cells and editor |
|
|
@@ -471,6 +479,7 @@ const columns: ColumnDef<Employee>[] = [
|
|
|
471
479
|
| `filterType` | `"text" \| "exact" \| "number" \| "date" \| "select"` | Which filter controls the popup shows. Default follows `type` |
|
|
472
480
|
| `filterOptions` | `(string \| FilterOption)[]` | Choices for a `"select"` filter. Without it they are built from the data |
|
|
473
481
|
| `filterPlaceholder` | `string` | Placeholder of the text filter box |
|
|
482
|
+
| `filterDebounce` | `number` | Milliseconds to wait after typing in **this** column's text / exact / number filter before it is applied. Overrides the grid's `filterDebounce` (default 300). `0` applies on every keystroke |
|
|
474
483
|
| `filterIndicator` | `ComponentType<FilterIndicatorProps<T>>` | Your own component drawn instead of the default dot |
|
|
475
484
|
| `filterIndicatorClassName` / `filterIndicatorStyle` | `string` / `CSSProperties` | Classes and inline styles for this column's indicator button |
|
|
476
485
|
| `filterPopupClassName` / `filterPopupStyle` | `string` / `CSSProperties` | Classes and inline styles for this column's filter popup |
|
|
@@ -492,6 +501,34 @@ const columns: ColumnDef<Employee>[] = [
|
|
|
492
501
|
| `checkbox` | `ColumnCheckboxOptions` | Look of the checkbox in a `type: "boolean"` column: `variant`, `indicator`, `className`, `style`, `classNames`, `styles` |
|
|
493
502
|
| `headerCheckbox` | `boolean` | On a `type: "boolean"` column, draws a select-all checkbox in the header. See [Select-all header checkbox](#select-all-header-checkbox) |
|
|
494
503
|
|
|
504
|
+
#### Row numbers (sequence column)
|
|
505
|
+
|
|
506
|
+
`type: "sequence"` adds a column of row numbers. It needs no data in your rows: give it a `field` that starts with `#` (so it can never clash with a real field) and a header.
|
|
507
|
+
|
|
508
|
+
```tsx
|
|
509
|
+
const columns: ColumnDef<Person>[] = [
|
|
510
|
+
{ field: "#", type: "sequence", headerName: "No.", width: 64, align: "center" },
|
|
511
|
+
{ field: "name", sortable: true, filterable: true },
|
|
512
|
+
{ field: "email" },
|
|
513
|
+
];
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
- The number is the row's **position in the list the user is looking at**. After a search or a filter the numbers start again at 1, and after sorting they follow the new order.
|
|
517
|
+
- With pagination the count **continues** on the next pages (page 2 starts at 11). Set `sequenceRestartEachPage: true` to start at `sequenceStart` on every page.
|
|
518
|
+
- `sequenceStart` changes the first number: `sequenceStart: 0` counts from 0.
|
|
519
|
+
- In server-side mode the number is `page * pageSize + position`, so page 3 of 10 rows starts at 21.
|
|
520
|
+
- The column is display-only: it cannot be sorted, filtered or edited, and it is skipped by the search. It can be pinned (`pinned: "left"`), resized and hidden like any other. The header defaults to `#`.
|
|
521
|
+
- `valueFormatter` works on it: `valueFormatter: (n) => String(n).padStart(3, "0")` gives `001`, `002`, ...
|
|
522
|
+
- CSV export includes it. A `scope: "page"` export numbers like the page does.
|
|
523
|
+
|
|
524
|
+
```tsx
|
|
525
|
+
// "No. 1", "No. 2", ... pinned on the left, starting after a header row of your own
|
|
526
|
+
{ field: "#", type: "sequence", sequenceStart: 1, pinned: "left", width: 70, valueFormatter: (n) => `No. ${n}` }
|
|
527
|
+
|
|
528
|
+
// restart on every page
|
|
529
|
+
{ field: "#", type: "sequence", sequenceRestartEachPage: true }
|
|
530
|
+
```
|
|
531
|
+
|
|
495
532
|
### 6.4 Sorting
|
|
496
533
|
|
|
497
534
|
**Sorting is chosen per column.** A column is sortable only when its definition says `sortable: true`. There is no grid-level switch.
|
|
@@ -589,7 +626,7 @@ Each column's filter has a kind. By default it follows the column `type`; set `f
|
|
|
589
626
|
| `"text"` | `type: "text"` | One text box | The displayed text **contains** the typed text (case-insensitive) |
|
|
590
627
|
| `"exact"` | | One text box | The displayed text **equals** the typed text (case-insensitive) |
|
|
591
628
|
| `"number"` | `type: "number"` | Min and Max boxes | The number is between Min and Max (either may be left empty). Rows without a number never match |
|
|
592
|
-
| `"date"` | `type: "date"` | From and To
|
|
629
|
+
| `"date"` | `type: "date"` | From and To boxes with a range calendar | The day is between From and To (either may be left empty) |
|
|
593
630
|
| `"select"` | `type: "boolean"` | A checkbox per value | The raw value is one of the ticked values |
|
|
594
631
|
|
|
595
632
|
```tsx
|
|
@@ -603,7 +640,7 @@ const columns: ColumnDef<Task>[] = [
|
|
|
603
640
|
// number range: type: "number" gives a Min / Max popup by default
|
|
604
641
|
{ field: "budget", type: "number", filterable: true },
|
|
605
642
|
|
|
606
|
-
// date range: type: "date" gives From / To
|
|
643
|
+
// date range: type: "date" gives From / To boxes and a calendar by default
|
|
607
644
|
{ field: "due", type: "date", filterable: true },
|
|
608
645
|
|
|
609
646
|
// choose from a list: values are collected from the data...
|
|
@@ -663,7 +700,7 @@ Every column has its own options:
|
|
|
663
700
|
}
|
|
664
701
|
```
|
|
665
702
|
|
|
666
|
-
The dot takes its colour from the button's text colour, so `color` (or `text-*`) restyles it. The colour while a filter is active comes from `--
|
|
703
|
+
The dot takes its colour from the button's text colour, so `color` (or `text-*`) restyles it. The colour while a filter is active comes from `--rg-filter-active`. To style all indicators or popups at once, use `classNames.filterIndicator`, `classNames.filterPopup`, `classNames.filterInput` (or the matching `styles`).
|
|
667
704
|
|
|
668
705
|
#### A custom indicator component
|
|
669
706
|
|
|
@@ -687,6 +724,36 @@ The component is drawn inside the indicator `<button>`, so do not put another bu
|
|
|
687
724
|
|
|
688
725
|
`filterRenderer` replaces **all** the built-in controls inside the popup, whatever the filter type (see [filterRenderer](#filterrenderer-custom-filter-control)). A custom control produces a text filter, so it works with the "contains" matching.
|
|
689
726
|
|
|
727
|
+
#### Debouncing typed filters
|
|
728
|
+
|
|
729
|
+
Typing in a text, exact or number filter does not apply the filter on every keystroke. The box updates at once, and the filter is applied once the user has stopped typing for a moment. This keeps a big grid responsive, and in [server-side mode](#615-server-side-mode) it means one request per pause instead of one per letter.
|
|
730
|
+
|
|
731
|
+
- The default wait is **300 ms**, set for the whole grid with `filterDebounce`.
|
|
732
|
+
- Any column can choose its own wait with `filterDebounce` in its definition (it wins over the grid's).
|
|
733
|
+
- `0` applies the filter on every keystroke.
|
|
734
|
+
- **Enter** applies a text or number filter immediately. Closing the popup also applies what is waiting, so typed text is never lost.
|
|
735
|
+
- **Clear**, or changing `filters` from outside, drops anything still waiting.
|
|
736
|
+
- Select checkboxes and date pickers are single clicks, so they apply at once. A custom `filterRenderer` also applies at once (debounce inside your component if you need it).
|
|
737
|
+
- The filter indicator lights up when the filter is applied, which is after the wait.
|
|
738
|
+
|
|
739
|
+
```tsx
|
|
740
|
+
// the whole grid waits 500 ms
|
|
741
|
+
<DataGrid filterDebounce={500} ... />
|
|
742
|
+
|
|
743
|
+
const columns: ColumnDef<Person>[] = [
|
|
744
|
+
{ field: "name", filterable: true }, // 500 ms (from the grid)
|
|
745
|
+
{ field: "email", filterable: true, filterDebounce: 800 }, // slow typers: 800 ms
|
|
746
|
+
{ field: "age", type: "number", filterable: true, filterDebounce: 0 }, // instant, a small local data set
|
|
747
|
+
{ field: "status", filterable: true, filterType: "select" }, // clicks: always instant
|
|
748
|
+
];
|
|
749
|
+
```
|
|
750
|
+
|
|
751
|
+
For a server grid you will often raise it, for a local grid you can lower it:
|
|
752
|
+
|
|
753
|
+
```tsx
|
|
754
|
+
<DataGrid serverSide filterDebounce={600} queryDebounce={400} onQueryChange={load} ... />
|
|
755
|
+
```
|
|
756
|
+
|
|
690
757
|
#### Notes
|
|
691
758
|
|
|
692
759
|
- Searching and text filters use the displayed text, so a salary shown as `$52,000` is found by `52,000` and not by `52000` unless your formatter says so. Number, date and select filters look at the raw value instead, so formatting never gets in their way.
|
|
@@ -718,7 +785,18 @@ const columns: ColumnDef<Task>[] = [
|
|
|
718
785
|
|
|
719
786
|
**What a row may hold.** The cell understands `"2026-11-05"`, a full ISO string (`"2026-11-05T10:30:00Z"`, whose date part is used as written), a `Date` object, a timestamp number, or any string `Date.parse` understands. Empty values show blank and sort last. Text that is not a date is shown as it is.
|
|
720
787
|
|
|
721
|
-
**Editing.** Double-click a date cell (or press Enter / F2)
|
|
788
|
+
**Editing.** Double-click a date cell (or press Enter / F2). A text box opens with a **calendar** under it:
|
|
789
|
+
|
|
790
|
+
- Click a day to save it at once. **Today** picks today and **Clear** saves an empty date (`null`).
|
|
791
|
+
- Or type the date as `YYYY-MM-DD`. The calendar follows what you type, and Enter (or a click elsewhere) saves it. Tab saves and moves on, Escape cancels.
|
|
792
|
+
- The arrows change month (`‹ ›`) and year (`« »`). Days before `dateMin` or after `dateMax` are dimmed and cannot be picked.
|
|
793
|
+
- Text that is not a real date (such as `2026-02-31`) marks the editor invalid and is not saved. Clicking away from it throws it away.
|
|
794
|
+
- Typing letters does not start an editor on a date cell: use double-click, Enter or F2.
|
|
795
|
+
- The calendar is drawn by the library, so it looks the same in every browser and follows your theme (`--rg-popup-*`, `--rg-primary`, `--rg-on-primary`). Month and weekday names follow `dateLocale`.
|
|
796
|
+
|
|
797
|
+
```tsx
|
|
798
|
+
{ field: "due", type: "date", editable: true, dateLocale: "fr-FR", dateMin: "2026-01-01" }
|
|
799
|
+
```
|
|
722
800
|
|
|
723
801
|
**The saved value keeps the shape the row already had.**
|
|
724
802
|
|
|
@@ -746,6 +824,8 @@ A `valueFormatter` still wins over these two if you set one.
|
|
|
746
824
|
<DataGrid filters={{ due: { from: "2026-03-01", to: "2026-06-30" } }} onFiltersChange={setFilters} ... />
|
|
747
825
|
```
|
|
748
826
|
|
|
827
|
+
**The date filter calendar.** The filter popup of a date column has From and To boxes and a calendar. Type the dates, or click on the calendar: the first click sets **From**, the second sets **To** (swapped if it is earlier), and a third click starts a new range. Days in the range are highlighted. With the keyboard, Tab into the calendar, then arrows move a day or a week, Page Up / Page Down change month, Home / End go to the start / end of the week, Enter picks.
|
|
828
|
+
|
|
749
829
|
**CSV export** writes dates as `"YYYY-MM-DD"` unless you give `exportValue`.
|
|
750
830
|
|
|
751
831
|
### 6.7 Pagination
|
|
@@ -793,10 +873,10 @@ Without `pagination` every row is rendered and there is no footer at all. Combin
|
|
|
793
873
|
/>
|
|
794
874
|
```
|
|
795
875
|
|
|
796
|
-
The toolbar row is drawn when at least one of `searchable`, `columnMenu`, `exportable` or `toolbar` is used. Your `toolbar` content sits on the right, next to the built-in buttons. To style a toolbar button the same way as the built-in ones, give it the class `
|
|
876
|
+
The toolbar row is drawn when at least one of `searchable`, `columnMenu`, `exportable` or `toolbar` is used. Your `toolbar` content sits on the right, next to the built-in buttons. To style a toolbar button the same way as the built-in ones, give it the class `rg-grid__tool-btn`:
|
|
797
877
|
|
|
798
878
|
```tsx
|
|
799
|
-
toolbar={<button className="
|
|
879
|
+
toolbar={<button className="rg-grid__tool-btn" onClick={refetch}>Reload</button>}
|
|
800
880
|
```
|
|
801
881
|
|
|
802
882
|
### 6.9 Editing
|
|
@@ -846,7 +926,7 @@ Details:
|
|
|
846
926
|
2. Otherwise, in a `type: "number"` column, an empty text stores `null`, a valid number stores that number, and anything else is rejected.
|
|
847
927
|
3. Otherwise the text is stored as a string.
|
|
848
928
|
|
|
849
|
-
**Validation.** After parsing, `validate(value, row)` is called. If it returns `false` (or a number could not be parsed), the value is not saved, the editor stays open, and it gets the `
|
|
929
|
+
**Validation.** After parsing, `validate(value, row)` is called. If it returns `false` (or a number could not be parsed), the value is not saved, the editor stays open, and it gets the `rg-grid__editor--invalid` class and `aria-invalid="true"`. Pressing Esc or clicking away discards the invalid text.
|
|
850
930
|
|
|
851
931
|
```tsx
|
|
852
932
|
{ field: "email", validate: (v) => /^\S+@\S+\.\S+$/.test(String(v)) }
|
|
@@ -1015,7 +1095,7 @@ How it behaves:
|
|
|
1015
1095
|
- **No text editor.** Boolean cells never open the text editor, and Enter and Tab navigation skip them. A click on the checkbox does not trigger `onRowClick`.
|
|
1016
1096
|
- **Sorting, search and filters.** Unchecked sorts before checked. Search and filters match the text `Yes` / `No`, or whatever your `valueFormatter` returns. A missing value (`null`, `undefined`) shows unchecked.
|
|
1017
1097
|
- **Header label.** The header of a boolean column is empty unless you set `headerName`. Screen readers still get the field name.
|
|
1018
|
-
- **Custom character.** `checkbox: { indicator: "★" }` draws that character instead of the default fill or tick when checked. Colour it with `--
|
|
1098
|
+
- **Custom character.** `checkbox: { indicator: "★" }` draws that character instead of the default fill or tick when checked. Colour it with `--rg-checkbox-color` (button variant) or `--rg-checkbox-tick` (tick variant), for example through `checkbox.styles.root`.
|
|
1019
1099
|
- **Defaults.** 1px border, no rounded corners. See [Checkbox](#5-checkbox).
|
|
1020
1100
|
- **A column with its own `cellEditor`** is treated as a normal editable column instead.
|
|
1021
1101
|
|
|
@@ -1027,7 +1107,7 @@ How it behaves:
|
|
|
1027
1107
|
| One column | `checkbox: { variant: "tick" }` |
|
|
1028
1108
|
| Whole grid, classes or inline styles | `classNames` / `styles` slots `checkbox`, `checkboxControl`, `checkboxIndicator` |
|
|
1029
1109
|
| One column, classes or inline styles | `checkbox: { className, style, classNames, styles, indicator }` (same parts as the standalone `Checkbox`) |
|
|
1030
|
-
| Colours and size | CSS variables such as `--
|
|
1110
|
+
| Colours and size | CSS variables such as `--rg-checkbox-color`, set on the grid's `className` / `style`, or per column in `checkbox.styles.root` |
|
|
1031
1111
|
|
|
1032
1112
|
```tsx
|
|
1033
1113
|
<DataGrid
|
|
@@ -1183,7 +1263,7 @@ When both are given, `style` wins over `styles.root`.
|
|
|
1183
1263
|
<DataGrid stripeColors={["#fef3c7", "#e0f2fe"]} /> // your two colours (implies striped)
|
|
1184
1264
|
```
|
|
1185
1265
|
|
|
1186
|
-
Rows alternate between the two colours, starting with the first. `stripeColors` sets `--
|
|
1266
|
+
Rows alternate between the two colours, starting with the first. `stripeColors` sets `--rg-stripe-a` and `--rg-stripe-b` on the grid. You can also set those variables in your own CSS or theme, and turn on `striped`. Hovering a row still highlights it (`--rg-row-hover`).
|
|
1187
1267
|
|
|
1188
1268
|
#### Row animation
|
|
1189
1269
|
|
|
@@ -1193,7 +1273,32 @@ When rows render (the first load, a new page, a sort, a search or a filter), the
|
|
|
1193
1273
|
<DataGrid animateRows={false} /> // turn it off
|
|
1194
1274
|
```
|
|
1195
1275
|
|
|
1196
|
-
Tune it with `--
|
|
1276
|
+
Tune it with `--rg-row-duration` (default `0.38s`) and `--rg-row-stagger` (default `28ms` per row, up to 24 rows). Changing page or sort also scrolls the grid's own scroll area smoothly back to the top. Visitors who ask their system for reduced motion get no animation (`prefers-reduced-motion`).
|
|
1277
|
+
|
|
1278
|
+
#### Custom row animation
|
|
1279
|
+
|
|
1280
|
+
Pass your own CSS class to replace the built-in slide-up. The class should set `animation`. Every row also gets the CSS variable `--rg-i` (its position on the page, 0 to 24), so a delay of `calc(var(--rg-i) * 40ms)` makes rows arrive one after another.
|
|
1281
|
+
|
|
1282
|
+
```css
|
|
1283
|
+
@keyframes fade-left { from { opacity: 0; transform: translateX(-24px); } to { opacity: 1; transform: none; } }
|
|
1284
|
+
.row-fade-left { animation: fade-left 0.45s ease-out both; animation-delay: calc(var(--rg-i, 0) * 45ms); }
|
|
1285
|
+
```
|
|
1286
|
+
|
|
1287
|
+
```tsx
|
|
1288
|
+
<DataGrid rowAnimationClassName="row-fade-left" ... />
|
|
1289
|
+
```
|
|
1290
|
+
|
|
1291
|
+
It can also be a function of the row, for example to animate new rows differently:
|
|
1292
|
+
|
|
1293
|
+
```tsx
|
|
1294
|
+
<DataGrid rowAnimationClassName={(row) => (row.isNew ? "row-flash" : "row-fade-left")} ... />
|
|
1295
|
+
```
|
|
1296
|
+
|
|
1297
|
+
With Tailwind, define the keyframes in your config and use the utility, for example `rowAnimationClassName="animate-fade-in-left [animation-delay:calc(var(--rg-i)*40ms)]"`.
|
|
1298
|
+
|
|
1299
|
+
- It runs on the same moments as the built-in animation: first render, a new page, sort, search or filter.
|
|
1300
|
+
- `animateRows={false}` turns every row animation off, custom or not. It is also skipped while `virtualize` is on.
|
|
1301
|
+
- Reduced motion: the built-in animation stops for people who ask for it. Your own class is yours to handle: wrap it in `@media (prefers-reduced-motion: no-preference) { ... }`.
|
|
1197
1302
|
|
|
1198
1303
|
#### Width
|
|
1199
1304
|
|
|
@@ -1205,30 +1310,32 @@ If you prefer writing CSS, these class names are stable.
|
|
|
1205
1310
|
|
|
1206
1311
|
| Class | Element |
|
|
1207
1312
|
| --- | --- |
|
|
1208
|
-
| `.
|
|
1209
|
-
| `.
|
|
1210
|
-
| `.
|
|
1211
|
-
| `.
|
|
1212
|
-
| `.
|
|
1213
|
-
| `.
|
|
1214
|
-
| `.
|
|
1215
|
-
| `.
|
|
1216
|
-
| `.
|
|
1217
|
-
| `.
|
|
1218
|
-
| `.
|
|
1219
|
-
| `.
|
|
1220
|
-
| `.
|
|
1221
|
-
| `.
|
|
1222
|
-
| `.
|
|
1223
|
-
| `.
|
|
1224
|
-
| `.
|
|
1225
|
-
| `.
|
|
1226
|
-
| `.
|
|
1227
|
-
| `.
|
|
1228
|
-
| `.
|
|
1229
|
-
| `.
|
|
1230
|
-
| `.
|
|
1231
|
-
| `.
|
|
1313
|
+
| `.rg-grid` | Root |
|
|
1314
|
+
| `.rg-grid__toolbar`, `.rg-grid__search` | Toolbar and search box |
|
|
1315
|
+
| `.rg-grid__scroll`, `.rg-grid__table`, `.rg-grid__thead`, `.rg-grid__tbody` | Table structure |
|
|
1316
|
+
| `.rg-grid__tr` | Every row |
|
|
1317
|
+
| `.rg-grid__th`, `.rg-grid__th--sortable`, `.rg-grid__th-content`, `.rg-grid__sort` | Header cells and sort arrow |
|
|
1318
|
+
| `.rg-grid__filter-btn`, `.rg-grid__filter-btn--active`, `.rg-grid__filter-btn--open`, `.rg-grid__filter-dot` | Filter indicator button and its default dot |
|
|
1319
|
+
| `.rg-grid-popup`, `.rg-grid__filter-input`, `.rg-grid__filter-clear` | Filter popup (in `document.body`), its text box and Clear button |
|
|
1320
|
+
| `.rg-grid__row`, `.rg-grid__row--stripe-a`, `.rg-grid__row--stripe-b`, `.rg-grid__row--enter`, `.rg-grid__row--clickable` | Body rows |
|
|
1321
|
+
| `.rg-grid__td`, `.rg-grid__td--editable`, `.rg-grid__td--editing` | Body cells |
|
|
1322
|
+
| `.rg-grid__editor`, `.rg-grid__editor--invalid`, `.rg-grid__custom-editor` | Editors |
|
|
1323
|
+
| `.rg-grid__empty` | Empty state |
|
|
1324
|
+
| `.rg-grid__checkbox-cell` | Wrapper around a checkbox in a boolean column (the checkbox's own classes start with `.rg-checkbox`, see [Checkbox](#5-checkbox)) |
|
|
1325
|
+
| `.rg-grid__footer`, `.rg-grid__footer--top` | Pagination bar (`data-position="top"` or `"bottom"`) |
|
|
1326
|
+
| `.rg-grid__count`, `.rg-grid__pagination`, `.rg-grid__page-size-label`, `.rg-grid__page-size`, `.rg-grid__page-btn`, `.rg-grid__page-info` | Pagination parts |
|
|
1327
|
+
| `.rg-grid__toolbar-left`, `.rg-grid__toolbar-actions` | The two halves of the toolbar (search and selected count / buttons) |
|
|
1328
|
+
| `.rg-grid__tool-btn`, `.rg-grid__selected-count` | Toolbar buttons and the "N selected" label |
|
|
1329
|
+
| `.rg-grid__select-cell`, `.rg-grid__row--selected` | Row-selection checkbox cell and a selected row |
|
|
1330
|
+
| `.rg-grid__pinned`, `.rg-grid__pinned--left`, `.rg-grid__pinned--right`, `.rg-grid__pinned--edge` | Pinned cells (the edge class marks the last left / first right one) |
|
|
1331
|
+
| `.rg-grid__resizer` | The column resize handle |
|
|
1332
|
+
| `.rg-grid__sort-order` | The priority number next to a sort arrow in multi-column sort |
|
|
1333
|
+
| `.rg-grid--virtual`, `.rg-grid__spacer` | Virtualized grid and its spacer rows |
|
|
1334
|
+
| `.rg-grid__skeleton`, `.rg-grid__skeleton-row`, `.rg-grid__skeleton-cell` | Loading placeholder bar, row and (custom) cell |
|
|
1335
|
+
| `.rg-cal`, `.rg-cal__head`, `.rg-cal__nav`, `.rg-cal__title`, `.rg-cal__grid`, `.rg-cal__dow`, `.rg-cal__foot`, `.rg-cal__link` | The calendar: frame, month bar and arrows, weekday names, footer buttons |
|
|
1336
|
+
| `.rg-cal__day`, `.rg-cal__day--today`, `.rg-cal__day--selected`, `.rg-cal__day--in-range`, `.rg-cal__day--range-start`, `.rg-cal__day--range-end`, `.rg-cal__day--outside` | A day button and its states |
|
|
1337
|
+
| `.rg-grid__error` | The error message cell (with the Retry button) |
|
|
1338
|
+
| `.rg-grid__filter-fields`, `.rg-grid__filter-field`, `.rg-grid__filter-options`, `.rg-grid__filter-empty` | Controls inside the filter popup (number, date, select) |
|
|
1232
1339
|
|
|
1233
1340
|
|
|
1234
1341
|
### 6.12 Nested fields
|
|
@@ -1272,7 +1379,7 @@ Off by default. `rowSelection` adds a checkbox column on the left.
|
|
|
1272
1379
|
| `true` or `"multiple"` | Many rows. The header has a select-all checkbox. Shift+click selects a range |
|
|
1273
1380
|
| `"single"` | One row at a time (selecting another replaces it). No select-all checkbox |
|
|
1274
1381
|
|
|
1275
|
-
- Selected rows get the class `
|
|
1382
|
+
- Selected rows get the class `rg-grid__row--selected`, the colour `--rg-selected-bg` and `aria-selected="true"`.
|
|
1276
1383
|
- Selection is kept **by row id**, so it survives paging, sorting, searching and filtering. Pass `getRowId` so ids are stable.
|
|
1277
1384
|
- The **select-all checkbox** in the header acts on every selectable row that matches the current search and filters, **across all pages**. It shows a dash while only some of them are selected.
|
|
1278
1385
|
- **Shift+click** on a row's checkbox selects (or clears) everything between it and the last row you clicked, as shown on screen. Disabled rows in between are skipped.
|
|
@@ -1436,7 +1543,7 @@ When your data lives on a server, switch on `serverSide`. The grid then **does n
|
|
|
1436
1543
|
/>
|
|
1437
1544
|
```
|
|
1438
1545
|
|
|
1439
|
-
`onQueryChange(query)` is called **on mount and whenever the query changes**: the sort, the search text (after `queryDebounce` ms), a filter, the page or the page size. The query is:
|
|
1546
|
+
`onQueryChange(query)` is called **on mount and whenever the query changes**: the sort, the search text (after `queryDebounce` ms), a filter (after `filterDebounce` ms when typed), the page or the page size. The query is:
|
|
1440
1547
|
|
|
1441
1548
|
```ts
|
|
1442
1549
|
interface GridQuery {
|
|
@@ -1525,7 +1632,7 @@ const { data, isFetching } = useQuery(...);
|
|
|
1525
1632
|
api.current?.refresh();
|
|
1526
1633
|
```
|
|
1527
1634
|
|
|
1528
|
-
**
|
|
1635
|
+
**Debounce.** Typing in the search box waits `queryDebounce` milliseconds (250 by default) after the last keystroke, and typing in a column filter waits `filterDebounce` (300 by default, also settable per column), so fast typing makes one request, not one per letter. Set either to `0` for instant queries. Select checkboxes, date pickers, sorting and paging query immediately.
|
|
1529
1636
|
|
|
1530
1637
|
**Server mode and the other features.**
|
|
1531
1638
|
|
|
@@ -1545,8 +1652,8 @@ While loading, the body shows **placeholder rows** with shimmering bars instead
|
|
|
1545
1652
|
- `loadingRows` is how many placeholder rows to draw. Default: the page size (at most 20), or 5 without pagination.
|
|
1546
1653
|
- With `rowSelection` the checkbox column shows a small bar too.
|
|
1547
1654
|
- Bar widths vary slightly from row to row so the placeholder does not look like identical stripes.
|
|
1548
|
-
- Colours come from `--
|
|
1549
|
-
- Style the bars with `classNames.skeleton` / `styles.skeleton` (they are `<span class="
|
|
1655
|
+
- Colours come from `--rg-skeleton-a` and `--rg-skeleton-b`. Each theme sets them. The shimmer stops when the user has "reduce motion" turned on.
|
|
1656
|
+
- Style the bars with `classNames.skeleton` / `styles.skeleton` (they are `<span class="rg-grid__skeleton">`).
|
|
1550
1657
|
|
|
1551
1658
|
**A custom skeleton for each row.** Pass a component as `skeletonRow`. It is drawn once per placeholder row, inside a single cell that spans the whole row, and receives `{ rowIndex, columns }`:
|
|
1552
1659
|
|
|
@@ -1566,13 +1673,13 @@ function PersonSkeleton({ rowIndex }: SkeletonRowProps<Person>) {
|
|
|
1566
1673
|
<DataGrid serverSide onQueryChange={load} skeletonRow={PersonSkeleton} loadingRows={6} ... />
|
|
1567
1674
|
```
|
|
1568
1675
|
|
|
1569
|
-
You can reuse the built-in shimmer in your own placeholder by giving your elements the class `
|
|
1676
|
+
You can reuse the built-in shimmer in your own placeholder by giving your elements the class `rg-grid__skeleton`:
|
|
1570
1677
|
|
|
1571
1678
|
```tsx
|
|
1572
1679
|
function RowSkeleton({ columns }: SkeletonRowProps<Person>) {
|
|
1573
1680
|
return (
|
|
1574
1681
|
<div style={{ display: "grid", gridTemplateColumns: `repeat(${columns.length}, 1fr)`, gap: 16 }}>
|
|
1575
|
-
{columns.map((c) => <span key={c.field} className="
|
|
1682
|
+
{columns.map((c) => <span key={c.field} className="rg-grid__skeleton" style={{ width: "70%" }} />)}
|
|
1576
1683
|
</div>
|
|
1577
1684
|
);
|
|
1578
1685
|
}
|
|
@@ -1586,7 +1693,7 @@ Define the skeleton component at module level (not inline in render), like every
|
|
|
1586
1693
|
<DataGrid columns={columns} rows={rows} loading={isLoading} />
|
|
1587
1694
|
```
|
|
1588
1695
|
|
|
1589
|
-
**The error state.** If the promise from `onQueryChange` rejects, the body shows `errorMessage` (default "Could not load the data.") and a Retry button. Style it with `.
|
|
1696
|
+
**The error state.** If the promise from `onQueryChange` rejects, the body shows `errorMessage` (default "Could not load the data.") and a Retry button. Style it with `.rg-grid__error`:
|
|
1590
1697
|
|
|
1591
1698
|
```tsx
|
|
1592
1699
|
<DataGrid serverSide onQueryChange={load} errorMessage={<strong>The server is not answering.</strong>} ... />
|
|
@@ -1625,9 +1732,9 @@ const columns: ColumnDef<Employee>[] = [
|
|
|
1625
1732
|
<DataGrid columns={columns} rows={rows} /> // scroll sideways: ID, Name and Status stay put
|
|
1626
1733
|
```
|
|
1627
1734
|
|
|
1628
|
-
The row-selection checkbox column is pinned too when any column is pinned left. A thin shadow line (`.
|
|
1735
|
+
The row-selection checkbox column is pinned too when any column is pinned left. A thin shadow line (`.rg-grid__pinned--edge`) marks where pinned columns end. Give pinned columns an explicit `width` for the cleanest look. Pinning needs the grid to be narrower than its columns, which happens when the columns' widths add up to more than the container.
|
|
1629
1736
|
|
|
1630
|
-
Colours: `--
|
|
1737
|
+
Colours: `--rg-pinned-bg` and `--rg-pinned-header-bg`. Stripes, hover and selection are layered on top.
|
|
1631
1738
|
|
|
1632
1739
|
**Showing and hiding.** Switch on `columnMenu` for a "Columns" button with a checkbox per column:
|
|
1633
1740
|
|
|
@@ -1750,7 +1857,7 @@ await fetch("/api/reports", { method: "POST", headers: { "Content-Type": "text/c
|
|
|
1750
1857
|
```tsx
|
|
1751
1858
|
<DataGrid
|
|
1752
1859
|
apiRef={api}
|
|
1753
|
-
toolbar={<button className="
|
|
1860
|
+
toolbar={<button className="rg-grid__tool-btn" onClick={() => api.current?.exportCsv({ filename: "all", includeHidden: true })}>Export everything</button>}
|
|
1754
1861
|
...
|
|
1755
1862
|
/>
|
|
1756
1863
|
```
|
|
@@ -1978,7 +2085,7 @@ Behaviours to be aware of:
|
|
|
1978
2085
|
- `virtualize` needs fixed-height rows. A cell with wrapped text will be cut off.
|
|
1979
2086
|
- Pinned columns only stick when the table is wider than its container.
|
|
1980
2087
|
- In `serverSide` mode the grid cannot export or select rows it has never loaded.
|
|
1981
|
-
- The
|
|
2088
|
+
- The date calendar starts weeks on Sunday and has no week numbers or time of day.
|
|
1982
2089
|
|
|
1983
2090
|
---
|
|
1984
2091
|
|
|
@@ -1993,13 +2100,13 @@ The repository contains a playground with one page per feature:
|
|
|
1993
2100
|
| Custom components (`#custom`) | `cellRenderer`, `cellEditor`, `headerRenderer`, a custom funnel `filterIndicator`, a per-column indicator style, a `filterRenderer` in the popup |
|
|
1994
2101
|
| Checkboxes (`#checkboxes`) | Boolean columns with the three variants, an empty-label header, a custom `★` character, select-all headers, locking, styling from outside, and a standalone `Checkbox` |
|
|
1995
2102
|
| Styling (`#styling`) | Tailwind classes and inline styles, column `className` / `style`, and `stripeColors` |
|
|
1996
|
-
| Pagination (`#pagination`) | Top, bottom and both, no pagination, the row animation toggle
|
|
2103
|
+
| Pagination (`#pagination`) | Top, bottom and both, no pagination, the row animation toggle with two **custom animation classes**, a **row-number (sequence) column**, and a **controlled page and search** grid driven by outside buttons |
|
|
1997
2104
|
| Nested fields (`#nested`) | `contact.phone` style dot paths: editing, search, filter, sort, and proof the original data is not mutated |
|
|
1998
2105
|
| Row selection (`#selection`) | Multiple and single modes, controlled ids, `isRowSelectable`, Shift+click ranges, select-all across pages, `apiRef.selectAll()`, a Delete button |
|
|
1999
2106
|
| Server-side (`#server`) | A fake 237-row database with 700 ms latency: server sorting, multi-sort, search debounce, filters, paging, the loading skeleton (default and custom row), and a switch that makes the request fail so you can see the error and Retry |
|
|
2000
2107
|
| Columns (`#columns`) | Resizing, pinned columns on both sides, the Columns menu, arrow-key navigation, CSV export with `exportValue`, multi-column sort |
|
|
2001
2108
|
| Large data (`#large`) | 20,000 virtualized rows with search, sorting and a theme |
|
|
2002
|
-
| Dates and filters (`#dates`) | `type: "date"` with the
|
|
2109
|
+
| Dates and filters (`#dates`) | `type: "date"` with the calendar editor and range-calendar filter, `dateMin` / `dateMax`, a `Date`-object column, from/to, number range, select and exact filters |
|
|
2003
2110
|
| Themes (`#themes`) | A switcher for none and all 8 themes |
|
|
2004
2111
|
|
|
2005
2112
|
Run it:
|
|
@@ -2015,19 +2122,79 @@ The Styling demo loads Tailwind from its CDN, so it needs an internet connection
|
|
|
2015
2122
|
|
|
2016
2123
|
---
|
|
2017
2124
|
|
|
2125
|
+
## 8. Development, building and publishing
|
|
2126
|
+
|
|
2127
|
+
### Project layout
|
|
2128
|
+
|
|
2129
|
+
```
|
|
2130
|
+
src/
|
|
2131
|
+
index.ts Public exports
|
|
2132
|
+
components/Checkbox/ Checkbox.tsx, checkbox.css
|
|
2133
|
+
components/DataGrid/
|
|
2134
|
+
DataGrid.tsx The grid (state, rendering, keyboard, selection, server mode, virtualization)
|
|
2135
|
+
types.ts All public types, with doc comments
|
|
2136
|
+
ColumnFilter.tsx The filter indicator and its popup (text, number, date, select)
|
|
2137
|
+
ColumnMenu.tsx The "Columns" show / hide menu
|
|
2138
|
+
Popup.tsx Portal popup used by the two above
|
|
2139
|
+
filters.ts Filter kinds, matching and select options
|
|
2140
|
+
dates.ts Date parsing and formatting helpers
|
|
2141
|
+
csv.ts CSV building and download
|
|
2142
|
+
hooks.ts useControlled and a layout-effect helper
|
|
2143
|
+
paths.ts Dot notation: FieldPath, getByPath, setByPath
|
|
2144
|
+
utils.ts Small helpers
|
|
2145
|
+
datagrid.css Layout and component styles (zero specificity)
|
|
2146
|
+
themes.css The 8 themes
|
|
2147
|
+
demo/ Playground (not published)
|
|
2148
|
+
examples/ One file per demo page
|
|
2149
|
+
vite.config.ts Library build
|
|
2150
|
+
vite.demo.config.ts Playground dev server
|
|
2151
|
+
```
|
|
2152
|
+
|
|
2153
|
+
### Scripts
|
|
2154
|
+
|
|
2155
|
+
| Command | Does |
|
|
2156
|
+
| --- | --- |
|
|
2157
|
+
| `npm run dev` | Starts the demo playground using the library source |
|
|
2158
|
+
| `npm run typecheck` | Runs the TypeScript compiler without emitting files |
|
|
2159
|
+
| `npm run build` | Builds `dist/`: ES module, CommonJS, bundled type definitions and `style.css` |
|
|
2160
|
+
|
|
2161
|
+
### Testing the built package in another app
|
|
2162
|
+
|
|
2163
|
+
```bash
|
|
2164
|
+
npm run build
|
|
2165
|
+
npm pack # creates react-gridix-0.1.0.tgz
|
|
2166
|
+
# in another project:
|
|
2167
|
+
npm install /path/to/react-gridix-0.1.0.tgz
|
|
2168
|
+
```
|
|
2169
|
+
|
|
2170
|
+
### Publishing to npm
|
|
2171
|
+
|
|
2172
|
+
1. Create an npm account, enable two-factor authentication, and run `npm login`.
|
|
2173
|
+
2. Check the name is free with `npm view react-gridix`. If taken, rename the package, for example `@yourname/react-gridix` (scoped packages need `npm publish --access public`).
|
|
2174
|
+
3. In `package.json` fill in `author`, `repository`, `homepage` and `bugs`, and put your name in the `LICENSE` file (it says `YOUR NAME`).
|
|
2175
|
+
4. Run `npm run typecheck` and `npm run build`. `prepublishOnly` runs both automatically on `npm publish`. Confirm `dist/` contains `react-gridix.js`, `react-gridix.cjs`, `index.d.ts` and `style.css`.
|
|
2176
|
+
5. Run `npm publish --dry-run` and check that only `dist/`, `package.json`, `README.md` and `LICENSE` are listed.
|
|
2177
|
+
6. Run `npm publish`.
|
|
2178
|
+
7. For later releases bump the version first (`npm version patch`, `minor` or `major`). npm will not accept the same version twice. This release changes defaults (see [section 10](#10-migrating-from-the-earlier-version)), so a `minor` bump while below 1.0 (or `major` after) is appropriate.
|
|
2179
|
+
|
|
2180
|
+
---
|
|
2181
|
+
|
|
2018
2182
|
## 9. Troubleshooting
|
|
2019
2183
|
|
|
2020
2184
|
| Problem | Cause and fix |
|
|
2021
2185
|
| --- | --- |
|
|
2022
2186
|
| Everything looks unstyled | Import `react-gridix/style.css` once in your app |
|
|
2023
|
-
| `theme="ocean"` does nothing | The theme CSS ships in `style.css`: make sure it is imported. The attribute `data-
|
|
2187
|
+
| `theme="ocean"` does nothing | The theme CSS ships in `style.css`: make sure it is imported. The attribute `data-rg-theme` should appear on the grid root |
|
|
2024
2188
|
| Headers don't sort | Sorting is per column: add `sortable: true` to the column definition. There is no grid-level `sortable` prop any more |
|
|
2025
2189
|
| There is no search box | Pass `searchable` |
|
|
2026
2190
|
| There is no page info or page buttons | Pass `pagination`. Without it every row is shown and there is no footer |
|
|
2027
2191
|
| I can't find the filter input | Filters are per column: set `filterable: true`, then click the dot in the header |
|
|
2028
2192
|
| A date column shows `2026-11-05` instead of `Nov 5, 2026` | The column needs `type: "date"` |
|
|
2029
|
-
| The date
|
|
2193
|
+
| The date calendar never opens | The cell must be editable (`editable` on the grid or the column), then double-click it or press Enter / F2 |
|
|
2194
|
+
| A sequence column shows nothing or a type error | Give it `type: "sequence"` and a `field` that starts with `#`, for example `{ field: "#", type: "sequence" }` |
|
|
2195
|
+
| My custom row animation does nothing | `animateRows` is `false`, `virtualize` is on, or your class does not set `animation`. Check that the keyframes exist and that the class name is spelled the same in CSS |
|
|
2030
2196
|
| The number filter popup asks for Min and Max, but I wanted text | Number columns default to a range filter. Set `filterType: "text"` |
|
|
2197
|
+
| A typed filter feels slow, or fires on every key | Change the wait with `filterDebounce` on the grid (default 300 ms) or on one column. Use `0` for no waiting |
|
|
2031
2198
|
| Select filter lists the wrong labels | Pass `filterOptions` with `{ value, label }` pairs. `value` must equal what is stored in the row |
|
|
2032
2199
|
| Selecting rows does nothing | Add `rowSelection`. Give the grid `getRowId` so selection survives sorting and paging |
|
|
2033
2200
|
| The server grid asks for data twice on mount | In React StrictMode (development) effects run twice. The production build calls it once. Your handler should be safe to call repeatedly |
|
|
@@ -2057,6 +2224,27 @@ The Styling demo loads Tailwind from its CDN, so it needs an internet connection
|
|
|
2057
2224
|
|
|
2058
2225
|
## 10. Migrating from the earlier version
|
|
2059
2226
|
|
|
2227
|
+
### Renamed: react-gridix
|
|
2228
|
+
|
|
2229
|
+
The library is now **`react-gridix`**, and every CSS prefix changed from `rk` to `rg`.
|
|
2230
|
+
|
|
2231
|
+
| Before | Now |
|
|
2232
|
+
| --- | --- |
|
|
2233
|
+
| `npm install react-ui-kit` | `npm install react-gridix` |
|
|
2234
|
+
| `import ... from "react-ui-kit"` | `import ... from "react-gridix"` |
|
|
2235
|
+
| `import "react-ui-kit/style.css"` | `import "react-gridix/style.css"` |
|
|
2236
|
+
| CSS variables `--rk-header-bg`, `--rk-primary`, ... | `--rg-header-bg`, `--rg-primary`, ... |
|
|
2237
|
+
| Classes `.rk-grid__row`, `.rk-checkbox`, ... | `.rg-grid__row`, `.rg-checkbox`, ... |
|
|
2238
|
+
| Theme selector `[data-rk-theme="brand"]` | `[data-rg-theme="brand"]` |
|
|
2239
|
+
|
|
2240
|
+
Search your project's CSS for `rk-` and replace it with `rg-`. A one-line fix in a Unix shell: `sed -i 's/\brk-/rg-/g' src/**/*.css`.
|
|
2241
|
+
|
|
2242
|
+
### Other changes
|
|
2243
|
+
|
|
2244
|
+
Also new in this release: `filterDebounce`, a smaller default checkbox (17px instead of 20px, with a tighter gap and a narrower selection column), a calendar for date cells and date filters, the `sequence` column type, `rowAnimationClassName`, and re-tuned theme colours (stronger header contrast, clearer inputs in the dark themes).
|
|
2245
|
+
|
|
2246
|
+
### Changed defaults
|
|
2247
|
+
|
|
2060
2248
|
Three defaults changed so that every feature is opt-in.
|
|
2061
2249
|
|
|
2062
2250
|
| Before | Now | What to do |
|