From c1501b06c525609245de04fd6a03cc6fc59cde01 Mon Sep 17 00:00:00 2001 From: Kevin Van Cott Date: Sun, 2 Aug 2026 07:07:55 -0500 Subject: [PATCH] fix: ensure isSubRowSelected returns false if no subRows are selectable A parent row whose sub-rows are all unselectable fell through with allChildrenSelected still true, so isSubRowSelected reported 'all' and getIsAllSubRowsSelected returned true with nothing selected. Track whether any selectable descendant was seen and return false when none were. Port of #5790 to v9. Fixes #5173 Co-Authored-By: Joel 'Aaron' Cohen Co-Authored-By: Claude Fable 5 --- .../rowSelectionFeature.utils.ts | 7 +++ .../row-selection/rowSelectionFeature.test.ts | 46 +++++++++++++++++++ .../rowSelectionFeature.utils.test.ts | 8 ++++ 3 files changed, 61 insertions(+) diff --git a/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts b/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts index 02f4e6a181..0419d1d9a5 100644 --- a/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts +++ b/packages/table-core/src/features/row-selection/rowSelectionFeature.utils.ts @@ -907,6 +907,7 @@ export function isSubRowSelected< let someSelected = false let allChildrenSelected = true + let someSelectable = false for (let i = 0; i < row.subRows.length; i++) { const subRow = row.subRows[i]! @@ -917,6 +918,7 @@ export function isSubRowSelected< } if (row_getCanSelect(subRow)) { + someSelectable = true if (isRowSelected(subRow, rowSelection)) { someSelected = true } else { @@ -929,14 +931,19 @@ export function isSubRowSelected< const subRowChildrenSelected = isSubRowSelected(subRow) if (subRowChildrenSelected === 'all') { someSelected = true + someSelectable = true } else if (subRowChildrenSelected === 'some') { someSelected = true allChildrenSelected = false + someSelectable = true } else { allChildrenSelected = false } } } + // A row with no selectable descendants can never be in a selected state + if (!someSelectable) return false + return allChildrenSelected ? 'all' : someSelected ? 'some' : false } diff --git a/packages/table-core/tests/implementation/features/row-selection/rowSelectionFeature.test.ts b/packages/table-core/tests/implementation/features/row-selection/rowSelectionFeature.test.ts index fec266e5cc..640cf4f933 100644 --- a/packages/table-core/tests/implementation/features/row-selection/rowSelectionFeature.test.ts +++ b/packages/table-core/tests/implementation/features/row-selection/rowSelectionFeature.test.ts @@ -416,6 +416,52 @@ describe('rowSelectionFeature', () => { expect(result).toEqual(false) }) + it('should return false if no sub-rows are selectable', () => { + const data = generateTestData(3, 2) + const columns = generateColumnDefs(data) + + const table = constructTable({ + features, + enableRowSelection: false, + renderFallbackValue: '', + data, + getSubRows: (originalRow: Person, _idx: number) => originalRow.subRows, + initialState: { + rowSelection: {}, + }, + columns, + }) + + const firstRow = table.getCoreRowModel().rows[0]! + + const result = RowSelectionUtils.isSubRowSelected(firstRow) + + expect(result).toEqual(false) + }) + + it('should return some if no children are selectable, but a grand-child is and is selected', () => { + const data = generateTestData(3, 2, 2) + const columns = generateColumnDefs(data) + + const table = constructTable({ + features, + enableRowSelection: (row) => row.id === '0.0.1', + renderFallbackValue: '', + data, + getSubRows: (originalRow: Person, _idx: number) => originalRow.subRows, + initialState: { + rowSelection: { '0.0.1': true }, + }, + columns, + }) + + const firstRow = table.getCoreRowModel().rows[0]! + + const result = RowSelectionUtils.isSubRowSelected(firstRow) + + expect(result).toEqual('some') + }) + it('should return some if some sub-rows are selected', () => { const data = generateTestData(3, 2) const columns = generateColumnDefs(data) diff --git a/packages/table-core/tests/unit/features/row-selection/rowSelectionFeature.utils.test.ts b/packages/table-core/tests/unit/features/row-selection/rowSelectionFeature.utils.test.ts index 6dde5d139a..c67271f4e6 100644 --- a/packages/table-core/tests/unit/features/row-selection/rowSelectionFeature.utils.test.ts +++ b/packages/table-core/tests/unit/features/row-selection/rowSelectionFeature.utils.test.ts @@ -399,6 +399,14 @@ describe('row_getIsSomeSelected / row_getIsAllSubRowsSelected', () => { expect(row_getIsSomeSelected(row)).toBe(false) expect(row_getIsAllSubRowsSelected(row)).toBe(false) }) + + it('should report nothing when no sub-rows are selectable', () => { + const table = makeTable({ enableRowSelection: false }, [3, 2]) + const parent = table.getRow('0') + + expect(row_getIsSomeSelected(parent)).toBe(false) + expect(row_getIsAllSubRowsSelected(parent)).toBe(false) + }) }) describe('row selection flags', () => {