Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions packages/table-core/src/features/RowSelection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -431,12 +431,11 @@ export const RowSelection: TableFeature = {
}

table.getIsSomeRowsSelected = () => {
const totalSelected = Object.keys(
table.getState().rowSelection ?? {}
).length
const visibleRows = table.getFilteredRowModel().flatRows
const selectedVisibleRows = visibleRows.filter(row => row.getIsSelected())
return (
totalSelected > 0 &&
totalSelected < table.getFilteredRowModel().flatRows.length
selectedVisibleRows.length > 0 &&
selectedVisibleRows.length < visibleRows.length
)
Comment on lines +434 to 439
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Good fix; also exclude non-selectable rows and account for partial (subrow) selection to avoid new inconsistencies.

This change correctly scopes the calculation to the filtered (visible) set, fixing #6079. However:

  • It counts against all visible rows, including those that cannot be selected. This can incorrectly set the header to indeterminate when all selectable rows are selected but some visible rows are not selectable.
  • It ignores rows that are “partially selected” via subrows (getIsSomeSelected), which page-level logic already handles.

Align this with getIsSomePageRowsSelected by considering only selectable rows and including partial selection. Suggested diff:

-    const visibleRows = table.getFilteredRowModel().flatRows
-    const selectedVisibleRows = visibleRows.filter(row => row.getIsSelected())
-    return (
-      selectedVisibleRows.length > 0 &&
-      selectedVisibleRows.length < visibleRows.length
-    )
+    const visibleSelectableRows = table
+      .getFilteredRowModel()
+      .flatRows.filter(row => row.getCanSelect())
+    if (!visibleSelectableRows.length) return false
+    if (table.getIsAllRowsSelected()) return false
+    return visibleSelectableRows.some(
+      row => row.getIsSelected() || row.getIsSomeSelected()
+    )

This keeps behavior consistent with page-level helpers and prevents regressions when non-selectable rows are present in the filtered view.

I can add unit tests covering:

  • Selected rows filtered out vs. visible subset.
  • Presence of non-selectable rows alongside selectable ones.
  • Partial (subrow) selection affecting the indeterminate state.
📝 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.

Suggested change
const visibleRows = table.getFilteredRowModel().flatRows
const selectedVisibleRows = visibleRows.filter(row => row.getIsSelected())
return (
totalSelected > 0 &&
totalSelected < table.getFilteredRowModel().flatRows.length
selectedVisibleRows.length > 0 &&
selectedVisibleRows.length < visibleRows.length
)
const visibleSelectableRows = table
.getFilteredRowModel()
.flatRows.filter(row => row.getCanSelect())
if (!visibleSelectableRows.length) return false
if (table.getIsAllRowsSelected()) return false
return visibleSelectableRows.some(
row => row.getIsSelected() || row.getIsSomeSelected()
)
🤖 Prompt for AI Agents
In packages/table-core/src/features/RowSelection.ts around lines 434 to 439, the
current visible-row indeterminate logic counts all visible rows and ignores
partial/subrow selection, which can mark the header indeterminate when only
non-selectable rows remain or miss when subrows are partially selected; update
the calculation to first filter visibleRows to only those with
row.getCanSelect(), then compute selectedVisibleRows as rows where
row.getIsSelected() OR row.getIsSomeSelected(), and finally return true when
selectedVisibleRows.length > 0 and selectedVisibleRows.length <
selectableVisibleRows.length so the indeterminate state matches
getIsSomePageRowsSelected and excludes non-selectable rows.

}

Expand Down