fix: correct row behavior and expand feature guides - #6509
Conversation
📝 WalkthroughWalkthroughThe PR refreshes TanStack Table documentation across framework adapters, adds new Features, Client-Side vs Server-Side, and FlexRender guides, and updates aggregation guidance. It also fixes paginated cell-selection navigation, recursively restores grouped-row relationships, and expands the React kitchen-sink selection example. ChangesDocumentation and navigation
Table interaction behavior
Estimated code review effort: 4 (Complex) | ~60 minutes Possibly related PRs
Sequence Diagram(s)sequenceDiagram
participant User
participant KitchenSink
participant CellSelection
participant TableRows
User->>KitchenSink: Select cells with mouse or keyboard
KitchenSink->>CellSelection: Update the selected range
CellSelection->>TableRows: Notify affected rows
TableRows-->>KitchenSink: Render selection and span states
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
View your CI Pipeline Execution ↗ for commit 4cca65a
☁️ Nx Cloud last updated this comment at |
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/table-core/src/features/cell-selection/cellSelectionFeature.utils.ts (1)
921-932: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winMerge-bounds lookup mixes row-model indices with display indices, and the new tests do not cover that path.
table_getCellSelectionMergeBoundsproduces bounds in display-index space, but the start-merge lookup instepCoordinatenow passes agetRowModel().rowsindex. The two indices diverge as soon as pagination or filtering removes rows above the current page, and the added tests use no cell spanning, so the divergence stays hidden.
packages/table-core/src/features/cell-selection/cellSelectionFeature.utils.ts#L921-L932: computerows[rowIndex]!.getDisplayIndex()once and pass it tofindMergeBoundsAt, matching the landing lookup at lines 994-999.packages/table-core/tests/implementation/features/cell-selection/cellSelectionFeature.test.ts#L481-L514: add a test with cell spanning enabled that moves out of a merged cell whilepageIndexis greater than 0.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/table-core/src/features/cell-selection/cellSelectionFeature.utils.ts` around lines 921 - 932, The start-merge lookup in stepCoordinate uses row-model indices instead of display indices. In packages/table-core/src/features/cell-selection/cellSelectionFeature.utils.ts#L921-L932, pass rows[rowIndex]!.getDisplayIndex() to findMergeBoundsAt while preserving the existing direction handling; in packages/table-core/tests/implementation/features/cell-selection/cellSelectionFeature.test.ts#L481-L514, add coverage with cell spanning enabled that moves out of a merged cell on a page where pageIndex is greater than 0.
🧹 Nitpick comments (4)
examples/react/kitchen-sink/src/routes/index.tsx (3)
1008-1008: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueAdd an accessible name and role to the focusable grid container.
The container is now focusable and receives arrow-key shortcuts. Screen-reader users get no indication of the interaction model. Add
role="grid"andaria-labelso the keyboard behavior is discoverable.♿ Proposed change
- <div className="table-container" ref={gridRef} tabIndex={0}> + <div + className="table-container" + ref={gridRef} + tabIndex={0} + role="grid" + aria-label="Kitchen sink data grid with cell selection" + >🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@examples/react/kitchen-sink/src/routes/index.tsx` at line 1008, Add role="grid" and a descriptive aria-label to the focusable table-container div using gridRef, so screen readers identify its grid interaction and keyboard navigation behavior.
509-547: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueHoist the
cell.getCanSelect()result into a local constant.The code calls
cell.getCanSelect()four times in one render pass. One local constant makes the gating explicit and avoids repeated calls.♻️ Proposed refactor
- const selectionClassNames = cell.getCanSelect() + const canSelect = cell.getCanSelect() + const selectionClassNames = canSelect ? (() => {- tabIndex={cell.getCanSelect() ? cell.getTabIndex() : undefined} - onMouseDown={ - cell.getCanSelect() ? cell.getSelectionStartHandler() : undefined - } - onMouseEnter={ - cell.getCanSelect() ? cell.getSelectionExtendHandler() : undefined - } + tabIndex={canSelect ? cell.getTabIndex() : undefined} + onMouseDown={canSelect ? cell.getSelectionStartHandler() : undefined} + onMouseEnter={canSelect ? cell.getSelectionExtendHandler() : undefined}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@examples/react/kitchen-sink/src/routes/index.tsx` around lines 509 - 547, In the cell render logic, assign cell.getCanSelect() to a local constant once and reuse it for selectionClassNames, tabIndex, onMouseDown, and onMouseEnter. Preserve the existing conditional behavior while eliminating the repeated method calls.
1033-1043: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueExtract the repeated cell-selection row subscription.
This
Subscribe+rowSelectionKeyblock is identical to the one inPinnedRowat lines 578-588. Extract one wrapper component and use it in both places.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@examples/react/kitchen-sink/src/routes/index.tsx` around lines 1033 - 1043, Extract the shared cell-selection subscription into a wrapper component that encapsulates Subscribe and rowSelectionKey, then replace the duplicated blocks in PinnedRow and the current row rendering with that component. Preserve the existing source, selection bounds, display index, row id, and key behavior at both call sites.packages/table-core/tests/implementation/features/cell-selection/cellSelectionFeature.test.ts (1)
481-514: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winAdd coverage for merged cells on a non-first page.
Both tests use a table without cell spanning, so display indices equal row-model indices. That combination hides the coordinate-space mismatch in the start-merge lookup in
cellSelectionFeature.utils.ts. Add a test that enables cell spanning and navigates from inside a merged cell whilepageIndexis greater than 0.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/table-core/tests/implementation/features/cell-selection/cellSelectionFeature.test.ts` around lines 481 - 514, The cell-selection pagination tests lack coverage for merged cells on a non-first page. Update the relevant tests around “keeps movement within the current pagination page” or add a focused case that enables cell spanning, sets pagination.pageIndex greater than 0, and navigates from inside a merged cell; assert selection remains within the current page and uses the correct merged-cell coordinates.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/framework/react/guide/flex-render.md`:
- Line 42: Update the FlexRender example so the footer prop references a defined
footer header: either introduce a Header object sourced from
table.getFooterGroups() or rename the existing variable to footerHeader and use
it consistently in the FlexRender call.
In `@docs/framework/solid/guide/column-filtering.md`:
- Line 318: Update the filterFn.autoRemove documentation sentence in the column
filtering guide so the example uses correct punctuation and capitalization:
replace “e.g. Some” with “e.g., some,” while preserving the rest of the
explanation.
In `@docs/guide/client-side-vs-server-side.md`:
- Line 49: Update the client-side row-capacity statement in the documentation to
qualify the 15-million-row benchmark as dependent on browser, page complexity,
columns, and available memory rather than claiming it is supported “with ease”;
preserve the practical-use caveat. Also correct the Object Prototypes Refactor
link by removing the duplicate slash in its URL.
In `@examples/react/kitchen-sink/src/index.css`:
- Around line 296-305: Add an empty line before the box-shadow declaration
following the --cell-edge-* custom properties to satisfy Stylelint’s
declaration-empty-line-before rule; leave the shadow values unchanged.
In `@examples/react/kitchen-sink/tests/e2e/smoke.spec.ts`:
- Around line 71-73: Update the sorting assertion in the smoke test to locate a
status cell with a rowspan value greater than 1, rather than requiring exactly
rowspan="2". Keep the visibility assertion, but make it target any rendered
spanned cell so it remains valid for the randomly generated data.
---
Outside diff comments:
In
`@packages/table-core/src/features/cell-selection/cellSelectionFeature.utils.ts`:
- Around line 921-932: The start-merge lookup in stepCoordinate uses row-model
indices instead of display indices. In
packages/table-core/src/features/cell-selection/cellSelectionFeature.utils.ts#L921-L932,
pass rows[rowIndex]!.getDisplayIndex() to findMergeBoundsAt while preserving the
existing direction handling; in
packages/table-core/tests/implementation/features/cell-selection/cellSelectionFeature.test.ts#L481-L514,
add coverage with cell spanning enabled that moves out of a merged cell on a
page where pageIndex is greater than 0.
---
Nitpick comments:
In `@examples/react/kitchen-sink/src/routes/index.tsx`:
- Line 1008: Add role="grid" and a descriptive aria-label to the focusable
table-container div using gridRef, so screen readers identify its grid
interaction and keyboard navigation behavior.
- Around line 509-547: In the cell render logic, assign cell.getCanSelect() to a
local constant once and reuse it for selectionClassNames, tabIndex, onMouseDown,
and onMouseEnter. Preserve the existing conditional behavior while eliminating
the repeated method calls.
- Around line 1033-1043: Extract the shared cell-selection subscription into a
wrapper component that encapsulates Subscribe and rowSelectionKey, then replace
the duplicated blocks in PinnedRow and the current row rendering with that
component. Preserve the existing source, selection bounds, display index, row
id, and key behavior at both call sites.
In
`@packages/table-core/tests/implementation/features/cell-selection/cellSelectionFeature.test.ts`:
- Around line 481-514: The cell-selection pagination tests lack coverage for
merged cells on a non-first page. Update the relevant tests around “keeps
movement within the current pagination page” or add a focused case that enables
cell spanning, sets pagination.pageIndex greater than 0, and navigates from
inside a merged cell; assert selection remains within the current page and uses
the correct merged-cell coordinates.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: d4e09f8d-eaae-45de-909b-21d429e229fa
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (95)
docs/config.jsondocs/framework/alpine/guide/aggregation.mddocs/framework/alpine/guide/column-filtering.mddocs/framework/alpine/guide/custom-features.mddocs/framework/alpine/guide/flex-render.mddocs/framework/alpine/guide/global-filtering.mddocs/framework/alpine/guide/pagination.mddocs/framework/alpine/guide/sorting.mddocs/framework/angular/guide/aggregation.mddocs/framework/angular/guide/column-filtering.mddocs/framework/angular/guide/custom-features.mddocs/framework/angular/guide/flex-render.mddocs/framework/angular/guide/global-filtering.mddocs/framework/angular/guide/migrating.mddocs/framework/angular/guide/pagination.mddocs/framework/angular/guide/sorting.mddocs/framework/angular/quick-start.mddocs/framework/ember/guide/aggregation.mddocs/framework/ember/guide/column-filtering.mddocs/framework/ember/guide/custom-features.mddocs/framework/ember/guide/flex-render.mddocs/framework/ember/guide/global-filtering.mddocs/framework/ember/guide/pagination.mddocs/framework/ember/guide/sorting.mddocs/framework/lit/guide/aggregation.mddocs/framework/lit/guide/column-filtering.mddocs/framework/lit/guide/custom-features.mddocs/framework/lit/guide/flex-render.mddocs/framework/lit/guide/global-filtering.mddocs/framework/lit/guide/pagination.mddocs/framework/lit/guide/sorting.mddocs/framework/octane/guide/aggregation.mddocs/framework/octane/guide/column-filtering.mddocs/framework/octane/guide/custom-features.mddocs/framework/octane/guide/flex-render.mddocs/framework/octane/guide/global-filtering.mddocs/framework/octane/guide/pagination.mddocs/framework/octane/guide/sorting.mddocs/framework/preact/guide/aggregation.mddocs/framework/preact/guide/column-filtering.mddocs/framework/preact/guide/custom-features.mddocs/framework/preact/guide/flex-render.mddocs/framework/preact/guide/global-filtering.mddocs/framework/preact/guide/pagination.mddocs/framework/preact/guide/sorting.mddocs/framework/react/guide/aggregation.mddocs/framework/react/guide/column-filtering.mddocs/framework/react/guide/custom-features.mddocs/framework/react/guide/flex-render.mddocs/framework/react/guide/global-filtering.mddocs/framework/react/guide/pagination.mddocs/framework/react/guide/sorting.mddocs/framework/solid/guide/aggregation.mddocs/framework/solid/guide/column-filtering.mddocs/framework/solid/guide/custom-features.mddocs/framework/solid/guide/flex-render.mddocs/framework/solid/guide/global-filtering.mddocs/framework/solid/guide/pagination.mddocs/framework/solid/guide/sorting.mddocs/framework/svelte/guide/aggregation.mddocs/framework/svelte/guide/column-filtering.mddocs/framework/svelte/guide/custom-features.mddocs/framework/svelte/guide/flex-render.mddocs/framework/svelte/guide/global-filtering.mddocs/framework/svelte/guide/pagination.mddocs/framework/svelte/guide/sorting.mddocs/framework/vanilla/guide/aggregation.mddocs/framework/vanilla/guide/flex-render.mddocs/framework/vue/guide/aggregation.mddocs/framework/vue/guide/column-filtering.mddocs/framework/vue/guide/custom-features.mddocs/framework/vue/guide/flex-render.mddocs/framework/vue/guide/global-filtering.mddocs/framework/vue/guide/pagination.mddocs/framework/vue/guide/sorting.mddocs/guide/aggregation.mddocs/guide/client-side-vs-server-side.mddocs/guide/column-defs.mddocs/guide/data.mddocs/guide/features.mddocs/reference/index/interfaces/ColumnDef_RowSorting.mddocs/reference/index/interfaces/TableOptions_Core.mddocs/reference/index/interfaces/TableOptions_RowPagination.mddocs/reference/index/interfaces/TableOptions_Rows.mdexamples/react/kitchen-sink/package.jsonexamples/react/kitchen-sink/src/index.cssexamples/react/kitchen-sink/src/routes/index.tsxexamples/react/kitchen-sink/tests/e2e/smoke.spec.tspackages/table-core/src/core/rows/coreRowsFeature.types.tspackages/table-core/src/features/cell-selection/cellSelectionFeature.utils.tspackages/table-core/src/features/column-grouping/createGroupedRowModel.tspackages/table-core/src/features/row-pagination/rowPaginationFeature.types.tspackages/table-core/src/features/row-sorting/rowSortingFeature.types.tspackages/table-core/tests/implementation/features/cell-selection/cellSelectionFeature.test.tspackages/table-core/tests/implementation/features/column-grouping/createGroupedRowModel.test.ts
💤 Files with no reviewable changes (1)
- docs/guide/aggregation.md
| ```tsx | ||
| import { FlexRender } from '@tanstack/react-table' | ||
|
|
||
| const footerContent = <FlexRender footer={header} /> |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Define the footer header used by this example.
header is not declared in this standalone snippet. Show a Header object from table.getFooterGroups() or rename the variable to footerHeader.
Proposed fix
-const footerContent = <FlexRender footer={header} />
+const footerHeader = table.getFooterGroups()[0].headers[0]
+const footerContent = <FlexRender footer={footerHeader} />🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/framework/react/guide/flex-render.md` at line 42, Update the FlexRender
example so the footer prop references a defined footer header: either introduce
a Header object sourced from table.getFooterGroups() or rename the existing
variable to footerHeader and use it consistently in the FlexRender call.
| - `filterFn.resolveDataValue` - This optional "hanging" method normalizes each row's value before it is compared against the filter value. It is honored by every filter function built with the `constructFilterFn` helper, which includes all built-in filter functions. | ||
|
|
||
| - `filterFn.autoRemove` - This optional "hanging" method on any given `filterFn` is passed a filter value and expected to return `true` if the filter value should be removed from the filter state. eg. Some boolean-style filters may want to remove the filter value from the table state if the filter value is set to `false`. When provided, this test is authoritative: values it keeps stay in filter state even when they are empty strings, which the default heuristic would otherwise remove. An `undefined` filter value always clears the filter regardless. | ||
| - `filterFn.autoRemove` - This optional "hanging" method on any given `filterFn` is passed a filter value and expected to return `true` if the filter value should be removed from the filter state. e.g. Some boolean-style filters may want to remove the filter value from the table state if the filter value is set to `false`. When provided, this test is authoritative: values it keeps stay in filter state even when they are empty strings, which the default heuristic would otherwise remove. An `undefined` filter value always clears the filter regardless. |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Correct the punctuation after e.g..
Line 318 continues the sentence after e.g., so use lowercase text and a comma: e.g., some boolean-style filters.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/framework/solid/guide/column-filtering.md` at line 318, Update the
filterFn.autoRemove documentation sentence in the column filtering guide so the
example uses correct punctuation and capitalization: replace “e.g. Some” with
“e.g., some,” while preserving the rest of the explanation.
|
|
||
| You might be tempted to rule out client-side processing based on what you think is a large dataset, but tables with just a few thousand rows are often practical in the browser. TanStack Table examples stress-test much larger datasets. In fact, we stress-test all TanStack Table features with 1 million rows client-side and expect usable performance. Actual performance depends on the number of columns, the size and shape of each row, the work performed by accessors and feature functions, and the devices your users have. Test with representative data and target hardware. | ||
|
|
||
| Older versions of TanStack Table used to start running into memory issues at about 1 million rows, but thanks to our [Object Prototypes Refactor](https://tanstack.com//blog/tanstack-table-v9-memory-performance) we can now claim to support up to 15 million rows client-side with ease. Is loading 15 million rows practical for your use-case? Probably not! But we hope you know that TanStack Table should give you headroom many client-side rows. |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== locate file =="
git ls-files | grep -F 'docs/guide/client-side-vs-server-side.md' || true
echo "== target excerpt =="
sed -n '35,60p' 'docs/guide/client-side-vs-server-side.md' 2>/dev/null || true
echo "== nearby mentions of row limits and memory/hardware caveats =="
rg -n "15 million|10–16|memory issues|hardware|caveat|TanStack Table" 'docs/guide/client-side-vs-server-side.md' 2>/dev/null || true
echo "== all instances of blog tanstack table v9 memory performance URL =="
rg -n "tanstack\.com//blog/tanstack-table-v9-memory-performance|tanstack\.com/blog/tanstack-table-v9-memory-performance" . 2>/dev/null || trueRepository: TanStack/table
Length of output: 7420
🌐 Web query:
tanstack blog tanstack-table-v9-memory-performance 15 million rows 4 GB benchmark
💡 Result:
TanStack Table V9 introduces significant memory optimizations compared to V8, enabling the library to handle much larger datasets in the browser [1][2]. According to official benchmarks, while TanStack Table V8 was typically limited to handling approximately 1 million to 1.5 million rows before hitting memory constraints (often around the 4GB mark), TanStack Table V9 can manage between 10 million and 16 million rows within that same 4GB memory limit [1][3]. This improvement is primarily driven by a refactor that moves table API methods (for rows, columns, headers, and cells) onto shared prototypes rather than recreating them for every instance [1][4][5]. This approach substantially reduces memory overhead for large tables, with some scenarios demonstrating up to a 90% reduction in retained heap usage compared to V8 [1][2]. The benchmarks were conducted using a custom testing suite that utilizes Playwright and the Chrome DevTools Protocol to measure retained heap size [1][6]. It is important to note that these figures are optimistic estimates; actual performance in a production environment will depend on the complexity of the web page, the number of features enabled, and other memory pressures [1]. As of July 2026, TanStack Table V9 is in beta, incorporating these optimizations as part of a broader architectural update focused on state management, tree-shakable features, and improved performance [7].
Citations:
- 1: https://tanstack.com/blog/tanstack-table-v9-memory-performance
- 2: https://tanstack.com/table/beta/docs/framework/react/guide/migrating
- 3: https://www.linkedin.com/posts/ivankuznetsov_over-the-last-30-days-rails-481-commits-activity-7486471485877035008-wPxl
- 4: https://github.com/TanStack/table/pull/5927/files
- 5: https://tanstack.com/blog/tanstack-table-v9-taking-form
- 6: feat: table memory blog post tanstack.com#1004
- 7: https://www.infoq.com/news/2026/07/tanstack-table-v9-beta/
Qualify the 15-million-row benchmark claim.
The benchmark supports a 10–16 million row result under a 4 GB limit, with actual browser performance depending on page complexity and columns. This line should not say “support up to 15 million … with ease,” and the URL contains a double slash.
Required link fix
-https://tanstack.com//blog/tanstack-table-v9-memory-performance
+https://tanstack.com/blog/tanstack-table-v9-memory-performance📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| Older versions of TanStack Table used to start running into memory issues at about 1 million rows, but thanks to our [Object Prototypes Refactor](https://tanstack.com//blog/tanstack-table-v9-memory-performance) we can now claim to support up to 15 million rows client-side with ease. Is loading 15 million rows practical for your use-case? Probably not! But we hope you know that TanStack Table should give you headroom many client-side rows. | |
| Older versions of TanStack Table used to start running into memory issues at about 1 million rows, but thanks to our [Object Prototypes Refactor](https://tanstack.com/blog/tanstack-table-v9-memory-performance) we can now claim to support up to 15 million rows client-side with ease. Is loading 15 million rows practical for your use-case? Probably not! But we hope you know that TanStack Table should give you headroom many client-side rows. |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/guide/client-side-vs-server-side.md` at line 49, Update the client-side
row-capacity statement in the documentation to qualify the 15-million-row
benchmark as dependent on browser, page complexity, columns, and available
memory rather than claiming it is supported “with ease”; preserve the
practical-use caveat. Also correct the Object Prototypes Refactor link by
removing the duplicate slash in its URL.
Source: MCP tools
| user-select: none; | ||
| --cell-edge-top: 0 0 0 0 transparent; | ||
| --cell-edge-right: 0 0 0 0 transparent; | ||
| --cell-edge-bottom: 0 0 0 0 transparent; | ||
| --cell-edge-left: 0 0 0 0 transparent; | ||
| box-shadow: | ||
| inset var(--cell-edge-top), | ||
| inset var(--cell-edge-right), | ||
| inset var(--cell-edge-bottom), | ||
| inset var(--cell-edge-left); |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Fix the Stylelint declaration-empty-line-before error.
Stylelint reports an error for the box-shadow declaration. Add an empty line before it.
🎨 Proposed fix
--cell-edge-left: 0 0 0 0 transparent;
+
box-shadow:
inset var(--cell-edge-top),📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| user-select: none; | |
| --cell-edge-top: 0 0 0 0 transparent; | |
| --cell-edge-right: 0 0 0 0 transparent; | |
| --cell-edge-bottom: 0 0 0 0 transparent; | |
| --cell-edge-left: 0 0 0 0 transparent; | |
| box-shadow: | |
| inset var(--cell-edge-top), | |
| inset var(--cell-edge-right), | |
| inset var(--cell-edge-bottom), | |
| inset var(--cell-edge-left); | |
| user-select: none; | |
| --cell-edge-top: 0 0 0 0 transparent; | |
| --cell-edge-right: 0 0 0 0 transparent; | |
| --cell-edge-bottom: 0 0 0 0 transparent; | |
| --cell-edge-left: 0 0 0 0 transparent; | |
| box-shadow: | |
| inset var(--cell-edge-top), | |
| inset var(--cell-edge-right), | |
| inset var(--cell-edge-bottom), | |
| inset var(--cell-edge-left); |
🧰 Tools
🪛 Stylelint (17.14.1)
[error] 301-305: Expected empty line before declaration (declaration-empty-line-before)
(declaration-empty-line-before)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@examples/react/kitchen-sink/src/index.css` around lines 296 - 305, Add an
empty line before the box-shadow declaration following the --cell-edge-* custom
properties to satisfy Stylelint’s declaration-empty-line-before rule; leave the
shadow values unchanged.
Source: Linters/SAST tools
| const statusHeader = table.locator('th').filter({ hasText: 'Status' }) | ||
| await statusHeader.locator('.sortable-header').click() | ||
| await expect(table.locator('tbody td[rowspan="2"]').first()).toBeVisible() |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
The exact rowspan="2" assertion can fail intermittently.
The route loads 1,000 randomly generated rows and the Status column has three possible values. After sorting by Status, adjacent equal values merge into runs. A run of exactly length 2 on the rendered page is not guaranteed; runs are usually longer. Assert that a spanned cell exists with a span greater than 1 instead.
🧪 Proposed fix
const statusHeader = table.locator('th').filter({ hasText: 'Status' })
await statusHeader.locator('.sortable-header').click()
- await expect(table.locator('tbody td[rowspan="2"]').first()).toBeVisible()
+ const spannedCell = table
+ .locator('tbody td[rowspan]')
+ .filter({ has: page.locator(':scope:not([rowspan="1"])') })
+ .first()
+ await expect(spannedCell).toBeVisible()
+ expect(
+ Number(await spannedCell.getAttribute('rowspan')),
+ ).toBeGreaterThan(1)
expect(errors).toEqual([])🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@examples/react/kitchen-sink/tests/e2e/smoke.spec.ts` around lines 71 - 73,
Update the sorting assertion in the smoke test to locate a status cell with a
rowspan value greater than 1, rather than requiring exactly rowspan="2". Keep
the visibility assertion, but make it target any rendered spanned cell so it
remains valid for the randomly generated data.
Summary
featuresoption produces smaller application bundlesFlexRenderguidesBug fixes
Cell-selection movement previously used the pre-pagination display-order model. Arrow-key movement could therefore select a row on another page that was not rendered. Movement now uses the final row model while preserving display indexes for merged-cell calculations.
Clearing grouping previously reset
depthandparentIdonly on top-level rows. Nested rows retained the shifted relationships written during grouping. The reset now recursively restores the natural tree structure for every descendant.Documentation
The documentation now introduces the v9 feature system as the first core guide, explains the bundle-size tradeoff behind explicit feature registration, and distinguishes features from optional client-side row models and function registries.
The new shared processing guide replaces repeated client-side versus server-side explanations while leaving concise links in each feature guide. Aggregation is now documented entirely within each framework guide, and every adapter has guidance for its own
FlexRenderandflexRenderAPIs.Validation
pnpm testpassed before PR creation and was not rerunpnpm test:e2epassed before PR creation and was not rerunpnpm test:docspassed with no broken links across 1,254 Markdown filesgit diff --checkpassedSummary by CodeRabbit
New Features
Bug Fixes
Documentation