…gs props
Fixes defects that showed users wrong data, closes accessibility gaps, and adds
the props consumers were working around.
Correctness
- showPagination={false} renders every row instead of silently keeping 10
- getRowId keeps selection on the record when rows are added or removed
- globalFilterFn runs once per row and no longer depends on first-row values
- text sorts case-insensitively with natural number order on small tables too
- editing a cell no longer jumps back to page 1
- searchKey works on number columns; an unknown key no longer blocks typing
- number cells never commit NaN and clamp to min/max; bad dates do not throw
- date-only strings show the right day in every timezone
- an in-progress edit survives parent re-renders
- explicit column sizes are honoured and no bogus max-width reaches the DOM
Accessibility
- resize handles work from the keyboard and are named per column
- sorted headers expose aria-sort
- focus returns to the cell after Enter or Escape
- row checkboxes and editable cells have distinct accessible names
New props
- className, getRowId, strings, loading, emptyState, onRowClick
- pageSizeOptions, pagination, onPaginationChange, manualPagination, rowCount
- searchValue, onSearchChange, showSelectionCount
- column meta: label, nullable
Behaviour changes are listed in the pull request description.
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Summary
Hardens the apollo-wind
DataTable(andEditableCell). An audit found 30+ defects, several of which silently showed users wrong data. This PR fixes them, closes the accessibility gaps, and adds the props consumers were working around. The public API is additive only.Demo
Side-by-side recording,
mainon the left and this branch on the right, same props on both sides (11 scenes, 92 s).data-table-before-after.mp4
Before and after
main)showPagination={false}with 25 rowsApple, Date, Elderberry, apple pie, bananagetRowId, selection stays on the record<body>NaNis committednullwithmeta.nullable),min/maxclampedRangeErrorglobalFilterFnwhen the first row has null or object valuessearchKeyon a number column2024-12-15Other fixes
aria-sort.max-width: 9007199254740991pxinline style on every cell, and an explicitsize: 150is honoured.maxBodyHeight: header and body stay aligned with classic (non-overlay) scrollbars.pageSizeprop changes after mount are respected. Empty data reads "Page 1 of 1".DataTableColumnHeadersupports Shift+click multi-sort and renders plain text for non-sortable columns.New props
className,getRowId,loading,emptyState,onRowClickstrings(Partial<DataTableStrings>): every built-in string, following the existingstringsconvention in this packagepageSizeOptions,pagination,onPaginationChange,manualPagination,rowCountsearchValue,onSearchChange,showSelectionCountmeta.labelandmeta.nullableNew exports:
DataTableStrings,DEFAULT_DATA_TABLE_STRINGS. Three new stories: "Editing with paging and selection", "Loading, empty state and row click", "Localization".Behaviour changes to review
No prop was removed or retyped, but these are visible to existing consumers:
selectcolumn, controlled selection, or a selected row (showSelectionCountoverrides)showPagination={false}renders all rowsdatachangesmaxBodyHeightand classic scrollbars, the scrollbar gutter is always reservedThe commit is typed
featwithout aBREAKING CHANGEfooter. If the accessible-name changes should count as breaking for semantic-release, that footer needs adding before merge.Regression and performance checks
DataTable.Old vs new on identical data, interleaved runs, median, in Chromium against the Storybook dev build (absolute numbers are inflated by React dev mode):
maxBodyHeightsearchKeykeystroke, 20,000 rowsglobalFilterFnkeystroke, no matchDifferences within about 5% are noise. Gzipped size of the two source files:
data-table2.8 KB to 5.6 KB,editable-cell1.5 KB to 1.8 KB.Not in this PR
Table.maxBodyHeightmode, columns without an explicitsizestill share width equally.Test plan
data-table.test.tsxandeditable-cell.test.tsx: 130 tests, run under a US timezoneNODE_OPTIONS=--no-experimental-webstorage(without it,form-plugins.test.tsxfails on Node 26, a file this PR does not touch)tsc --noEmit,biome lint,build🤖 Generated with Claude Code