react-gridix 0.2.0 → 0.2.2

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 CHANGED
@@ -1,4 +1,4 @@
1
- # react-gridix Docs
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. [Troubleshooting](#9-troubleshooting)
15
- 9. [Migrating from the earlier version](#10-migrating-from-the-earlier-version)
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-pink gradient header, serif font, rounded corners |
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, soft violet gradient header, rounded corners |
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 a green-to-blue-to-violet gradient header and a soft glow |
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-rk-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
+ 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-rk-theme="aurora"] { --rk-header-bg: #0f766e; }
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-rk-theme="brand"] {
192
- --rk-header-bg: #7c3aed;
193
- --rk-header-text: #fff;
194
- --rk-row-hover: #f5f3ff;
195
- --rk-selected-bg: #ede9fe; /* selected rows */
196
- --rk-primary: #7c3aed;
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 `--rk-surface`, `--rk-text`, `--rk-border`, `--rk-pinned-bg`, `--rk-skeleton-a` and `--rk-skeleton-b`. Copy the `graphite` block in `themes.css` as a starting point.
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
- | `--rk-font` | system UI stack | Font family |
213
- | `--rk-text` | `#111827` | Main text |
214
- | `--rk-muted` | `#6b7280` | Secondary text, empty state |
215
- | `--rk-border` | `#d1d5db` | Borders |
216
- | `--rk-surface` | `#ffffff` | Background of the grid, inputs, buttons |
217
- | `--rk-bg-subtle` | `#f3f4f6` | Header and footer background |
218
- | `--rk-primary` | `#4f46e5` | Focus rings, active editor border |
219
- | `--rk-danger` | `#dc2626` | Invalid editor border |
220
- | `--rk-invalid-bg` | `#fef2f2` | Invalid editor background |
221
- | `--rk-grid-bg` | `--rk-surface` | Grid background |
222
- | `--rk-grid-radius` | `10px` | Grid corner radius |
223
- | `--rk-grid-shadow` | `none` | Grid shadow |
224
- | `--rk-toolbar-bg` | `transparent` | Toolbar background |
225
- | `--rk-input-bg`, `--rk-input-border`, `--rk-input-text` | surface, border, inherit | Search box, filter inputs, editor, page controls |
226
- | `--rk-header-bg` | `--rk-bg-subtle` | Header background. Any CSS background, so gradients work |
227
- | `--rk-header-text` | inherit | Header text colour |
228
- | `--rk-header-hover-bg` | `rgba(0,0,0,.06)` | Header hover |
229
- | `--rk-header-border` | `--rk-border` | Line under the header |
230
- | `--rk-cell-border` | `#eef0f3` | Lines between rows |
231
- | `--rk-row-hover` | `#f3f4f6` | Row hover |
232
- | `--rk-selected-bg` | `#eef2ff` | Background of selected rows |
233
- | `--rk-pinned-bg` | `--rk-grid-bg` | Opaque background behind pinned body cells (so scrolled cells do not show through) |
234
- | `--rk-pinned-header-bg` | `--rk-bg-subtle` | Opaque background behind pinned header cells |
235
- | `--rk-skeleton-a`, `--rk-skeleton-b` | `#e5e7eb`, `#f3f4f6` | The two colours of the shimmering loading bars |
236
- | `--rk-stripe-a`, `--rk-stripe-b` | `transparent`, `#fafafa` | Alternating row colours (see [stripes](#striped-rows)) |
237
- | `--rk-footer-bg`, `--rk-footer-text` | subtle, muted | Pagination bar |
238
- | `--rk-btn-hover` | `#e5e7eb` | Page button, toolbar button and Clear button hover |
239
- | `--rk-filter-active` | `--rk-primary` | Filter dot colour while a filter is set |
240
- | `--rk-filter-glow` | `rgba(79,70,229,.25)` | Ring around an active filter dot |
241
- | `--rk-popup-bg`, `--rk-popup-text`, `--rk-popup-border` | white, dark, grey | Filter popup and column menu |
242
- | `--rk-popup-radius`, `--rk-popup-shadow` | `10px`, soft shadow | Popup shape |
243
- | `--rk-row-duration` | `0.38s` | Row entrance animation length |
244
- | `--rk-row-stagger` | `28ms` | Extra delay per row in the entrance animation |
245
- | `--rk-checkbox-size` | `20px` | Checkbox width and height |
246
- | `--rk-checkbox-border-width` | `1px` | Checkbox border width |
247
- | `--rk-checkbox-radius` | `0` | Checkbox corner radius (no rounding by default) |
248
- | `--rk-checkbox-color` | `#4f46e5` | Checked colour (also the focus ring and the native accent) |
249
- | `--rk-checkbox-border` | `#9ca3af` | Border colour of an unchecked `"button"` / `"tick"` checkbox |
250
- | `--rk-checkbox-bg` | `#ffffff` | Background of an unchecked `"button"` / `"tick"` checkbox |
251
- | `--rk-checkbox-tick` | `#ffffff` | Colour of the tick, and of a custom character in the `"tick"` variant |
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
- --rk-primary: #0d9488;
256
- --rk-row-hover: #f0fdfa;
257
- --rk-selected-bg: #ccfbf1;
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={{ "--rk-header-bg": "#0f172a", "--rk-header-text": "#fff" } as React.CSSProperties} ... />
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 `--rk-checkbox-color` variable for it.)
319
- 2. **CSS variables**: `--rk-checkbox-size`, `--rk-checkbox-border-width`, `--rk-checkbox-radius`, `--rk-checkbox-color`, `--rk-checkbox-border`, `--rk-checkbox-bg` and `--rk-checkbox-tick` (see [Theming](#42-css-variables)). Set them anywhere above the checkbox:
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: { "--rk-checkbox-color": "#dc2626" } as CSSProperties }} ... />
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 `--rk-checkbox-size`) and coloured with `--rk-checkbox-color` in the button variant and `--rk-checkbox-tick` in the tick variant. Restyle it through `classNames.indicator` / `styles.indicator`.
325
- 4. **Plain CSS** with these stable classes: `.rk-checkbox`, `.rk-checkbox--button`, `.rk-checkbox--tick`, `.rk-checkbox--native`, `.rk-checkbox--checked`, `.rk-checkbox--indeterminate`, `.rk-checkbox--disabled`, `.rk-checkbox__control`, `.rk-checkbox__indicator`, `.rk-checkbox__indicator--custom` and `.rk-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
+ 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 (`--rk-checkbox-border-width: 1px`, `--rk-checkbox-radius: 0`). Round them with `--rk-checkbox-radius: 999px` or a Tailwind `rounded-*` class on `classNames.control`.
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 date picker (see [6.6](#66-date-columns)). Default `"text"` |
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 date pickers | The day is between From and To (either may be left empty) |
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 date pickers by default
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 `--rk-filter-active`. To style all indicators or popups at once, use `classNames.filterIndicator`, `classNames.filterPopup`, `classNames.filterInput` (or the matching `styles`).
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) to open the browser's date picker. Typing characters does not start an editor on a date cell, because the picker is its own control. After picking or typing a valid date, Enter or a click elsewhere saves it. An empty picker saves `null`. Escape cancels. A half-typed date is ignored when you click away.
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 `rk-grid__tool-btn`:
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="rk-grid__tool-btn" onClick={refetch}>Reload</button>}
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 `rk-grid__editor--invalid` class and `aria-invalid="true"`. Pressing Esc or clicking away discards the invalid text.
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 `--rk-checkbox-color` (button variant) or `--rk-checkbox-tick` (tick variant), for example through `checkbox.styles.root`.
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 `--rk-checkbox-color`, set on the grid's `className` / `style`, or per column in `checkbox.styles.root` |
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 `--rk-stripe-a` and `--rk-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 (`--rk-row-hover`).
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 `--rk-row-duration` (default `0.38s`) and `--rk-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`).
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
- | `.rk-grid` | Root |
1209
- | `.rk-grid__toolbar`, `.rk-grid__search` | Toolbar and search box |
1210
- | `.rk-grid__scroll`, `.rk-grid__table`, `.rk-grid__thead`, `.rk-grid__tbody` | Table structure |
1211
- | `.rk-grid__tr` | Every row |
1212
- | `.rk-grid__th`, `.rk-grid__th--sortable`, `.rk-grid__th-content`, `.rk-grid__sort` | Header cells and sort arrow |
1213
- | `.rk-grid__filter-btn`, `.rk-grid__filter-btn--active`, `.rk-grid__filter-btn--open`, `.rk-grid__filter-dot` | Filter indicator button and its default dot |
1214
- | `.rk-grid-popup`, `.rk-grid__filter-input`, `.rk-grid__filter-clear` | Filter popup (in `document.body`), its text box and Clear button |
1215
- | `.rk-grid__row`, `.rk-grid__row--stripe-a`, `.rk-grid__row--stripe-b`, `.rk-grid__row--enter`, `.rk-grid__row--clickable` | Body rows |
1216
- | `.rk-grid__td`, `.rk-grid__td--editable`, `.rk-grid__td--editing` | Body cells |
1217
- | `.rk-grid__editor`, `.rk-grid__editor--invalid`, `.rk-grid__custom-editor` | Editors |
1218
- | `.rk-grid__empty` | Empty state |
1219
- | `.rk-grid__checkbox-cell` | Wrapper around a checkbox in a boolean column (the checkbox's own classes start with `.rk-checkbox`, see [Checkbox](#5-checkbox)) |
1220
- | `.rk-grid__footer`, `.rk-grid__footer--top` | Pagination bar (`data-position="top"` or `"bottom"`) |
1221
- | `.rk-grid__count`, `.rk-grid__pagination`, `.rk-grid__page-size-label`, `.rk-grid__page-size`, `.rk-grid__page-btn`, `.rk-grid__page-info` | Pagination parts |
1222
- | `.rk-grid__toolbar-left`, `.rk-grid__toolbar-actions` | The two halves of the toolbar (search and selected count / buttons) |
1223
- | `.rk-grid__tool-btn`, `.rk-grid__selected-count` | Toolbar buttons and the "N selected" label |
1224
- | `.rk-grid__select-cell`, `.rk-grid__row--selected` | Row-selection checkbox cell and a selected row |
1225
- | `.rk-grid__pinned`, `.rk-grid__pinned--left`, `.rk-grid__pinned--right`, `.rk-grid__pinned--edge` | Pinned cells (the edge class marks the last left / first right one) |
1226
- | `.rk-grid__resizer` | The column resize handle |
1227
- | `.rk-grid__sort-order` | The priority number next to a sort arrow in multi-column sort |
1228
- | `.rk-grid--virtual`, `.rk-grid__spacer` | Virtualized grid and its spacer rows |
1229
- | `.rk-grid__skeleton`, `.rk-grid__skeleton-row`, `.rk-grid__skeleton-cell` | Loading placeholder bar, row and (custom) cell |
1230
- | `.rk-grid__error` | The error message cell (with the Retry button) |
1231
- | `.rk-grid__filter-fields`, `.rk-grid__filter-field`, `.rk-grid__filter-options`, `.rk-grid__filter-empty` | Controls inside the filter popup (number, date, select) |
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 `rk-grid__row--selected`, the colour `--rk-selected-bg` and `aria-selected="true"`.
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
- **Search debounce.** Typing in the search box waits `queryDebounce` milliseconds (250 by default) after the last keystroke, so fast typing makes one request, not one per letter. Set `queryDebounce={0}` for instant queries.
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 `--rk-skeleton-a` and `--rk-skeleton-b`. Each theme sets them. The shimmer stops when the user has "reduce motion" turned on.
1549
- - Style the bars with `classNames.skeleton` / `styles.skeleton` (they are `<span class="rk-grid__skeleton">`).
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 `rk-grid__skeleton`:
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="rk-grid__skeleton" style={{ width: "70%" }} />)}
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 `.rk-grid__error`:
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 (`.rk-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.
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: `--rk-pinned-bg` and `--rk-pinned-header-bg`. Stripes, hover and selection are layered on top.
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="rk-grid__tool-btn" onClick={() => api.current?.exportCsv({ filename: "all", includeHidden: true })}>Export everything</button>}
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 browser's date picker looks different in each browser. Its language follows the browser, not `dateLocale` (which only formats the display).
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, and a **controlled page and search** grid driven by outside buttons |
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 date picker editor, `dateMin` / `dateMax`, a `Date`-object column, from/to, number range, select and exact filters |
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,22 @@ The Styling demo loads Tailwind from its CDN, so it needs an internet connection
2015
2122
 
2016
2123
  ---
2017
2124
 
2018
- ## 9. Troubleshooting
2125
+ ## 8. Troubleshooting
2019
2126
 
2020
2127
  | Problem | Cause and fix |
2021
2128
  | --- | --- |
2022
2129
  | 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-rk-theme` should appear on the grid root |
2130
+ | `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
2131
  | 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
2132
  | There is no search box | Pass `searchable` |
2026
2133
  | There is no page info or page buttons | Pass `pagination`. Without it every row is shown and there is no footer |
2027
2134
  | I can't find the filter input | Filters are per column: set `filterable: true`, then click the dot in the header |
2028
2135
  | A date column shows `2026-11-05` instead of `Nov 5, 2026` | The column needs `type: "date"` |
2029
- | The date picker never opens | The cell must be editable (`editable` on the grid or the column), then double-click it or press Enter / F2 |
2136
+ | 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 |
2137
+ | A sequence column shows nothing or a type error | Give it `type: "sequence"` and a `field` that starts with `#`, for example `{ field: "#", type: "sequence" }` |
2138
+ | 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
2139
  | The number filter popup asks for Min and Max, but I wanted text | Number columns default to a range filter. Set `filterType: "text"` |
2140
+ | 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
2141
  | Select filter lists the wrong labels | Pass `filterOptions` with `{ value, label }` pairs. `value` must equal what is stored in the row |
2032
2142
  | Selecting rows does nothing | Add `rowSelection`. Give the grid `getRowId` so selection survives sorting and paging |
2033
2143
  | 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 |
@@ -2055,7 +2165,7 @@ The Styling demo loads Tailwind from its CDN, so it needs an internet connection
2055
2165
 
2056
2166
  ---
2057
2167
 
2058
- ## 10. Migrating from the earlier version
2168
+ ### Changed defaults
2059
2169
 
2060
2170
  Three defaults changed so that every feature is opt-in.
2061
2171