feat(data-table): migrate to TanStack Table v9 - #1928
Conversation
📝 WalkthroughWalkthroughMigrates tables and documentation from TanStack Vue Table v8 to v9. The change adds shared feature registries, typed column helpers, reactive table atoms, updated rendering APIs, and removes the obsolete ChangesTanStack Table v9 migration
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant DataTable
participant features
participant useTable
participant FlexRender
DataTable->>features: provide registered table features
DataTable->>useTable: create typed table with columns and row selection
useTable->>FlexRender: provide header and cell instances
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 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 |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 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 `@apps/v4/components/demo/DataTableDemo.vue`:
- Around line 161-164: Update the DefineTemplate implementation used by
ReuseTemplate to accept and invoke the onExpand callback from the actions menu,
ensuring the menu action triggers row.toggleExpanded through the existing
onExpand prop.
In `@apps/v4/components/examples/tasks/components/DataTablePagination.vue`:
- Around line 39-41: Update the `@update`:model-value binding in
DataTablePagination to convert the emitted string page size to a number before
passing it to table.setPageSize, preserving the numeric pagination state
expected by the table API.
In `@apps/v4/content/docs/components/data-table.md`:
- Around line 1010-1011: Update the `@update`:model-value handler in the
pagination page-size control to convert the selected string value to a number
before passing it to table.setPageSize. Preserve the existing model-value
binding and ensure TanStack pagination state receives a numeric page size.
In `@apps/v4/registry/__index__.ts`:
- Around line 2352-2355: Remove the duplicate registry entry for
registry/new-york-v4/blocks/dashboard-01/components/features.ts from the
generated index, leaving exactly one entry consistent with the source manifest
and published output. Regenerate apps/v4/registry/__index__.ts; if regeneration
restores the duplicate, update the registry build step that produces it.
🪄 Autofix
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: 7eb9462d-0486-4ea4-9095-24943223bba7
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (55)
apps/v4/components/cards/Payments.vueapps/v4/components/demo/DataTableDemo.vueapps/v4/components/examples/dashboard/components/DataTable.vueapps/v4/components/examples/dashboard/components/DraggableRow.vueapps/v4/components/examples/dashboard/components/features.tsapps/v4/components/examples/tasks/components/DataTable.vueapps/v4/components/examples/tasks/components/DataTableColumnHeader.vueapps/v4/components/examples/tasks/components/DataTableFacetedFilter.vueapps/v4/components/examples/tasks/components/DataTablePagination.vueapps/v4/components/examples/tasks/components/DataTableRowActions.vueapps/v4/components/examples/tasks/components/DataTableToolbar.vueapps/v4/components/examples/tasks/components/DataTableViewOptions.vueapps/v4/components/examples/tasks/components/columns.tsapps/v4/components/examples/tasks/components/features.tsapps/v4/content/docs/03.components-json.mdapps/v4/content/docs/components/data-table.mdapps/v4/lib/utils.tsapps/v4/package.jsonapps/v4/public/r/index.jsonapps/v4/public/r/styles/new-york-v4/dashboard-01.jsonapps/v4/public/r/styles/new-york-v4/registry.jsonapps/v4/public/r/styles/new-york-v4/table.jsonapps/v4/public/r/styles/reka-luma/registry.jsonapps/v4/public/r/styles/reka-luma/table.jsonapps/v4/public/r/styles/reka-lyra/registry.jsonapps/v4/public/r/styles/reka-lyra/table.jsonapps/v4/public/r/styles/reka-maia/registry.jsonapps/v4/public/r/styles/reka-maia/table.jsonapps/v4/public/r/styles/reka-mira/registry.jsonapps/v4/public/r/styles/reka-mira/table.jsonapps/v4/public/r/styles/reka-nova/registry.jsonapps/v4/public/r/styles/reka-nova/table.jsonapps/v4/public/r/styles/reka-rhea/registry.jsonapps/v4/public/r/styles/reka-rhea/table.jsonapps/v4/public/r/styles/reka-sera/registry.jsonapps/v4/public/r/styles/reka-sera/table.jsonapps/v4/public/r/styles/reka-vega/registry.jsonapps/v4/public/r/styles/reka-vega/table.jsonapps/v4/registry/__index__.tsapps/v4/registry/bases/reka/ui/_registry.tsapps/v4/registry/bases/reka/ui/table/utils.tsapps/v4/registry/new-york-v4/blocks/_registry.tsapps/v4/registry/new-york-v4/blocks/dashboard-01/components/DataTable.vueapps/v4/registry/new-york-v4/blocks/dashboard-01/components/DraggableRow.vueapps/v4/registry/new-york-v4/blocks/dashboard-01/components/features.tsapps/v4/registry/new-york-v4/ui/_registry.tsapps/v4/registry/new-york-v4/ui/table/utils.tsapps/v4/styles/reka-luma/ui/table/utils.tsapps/v4/styles/reka-lyra/ui/table/utils.tsapps/v4/styles/reka-maia/ui/table/utils.tsapps/v4/styles/reka-mira/ui/table/utils.tsapps/v4/styles/reka-nova/ui/table/utils.tsapps/v4/styles/reka-rhea/ui/table/utils.tsapps/v4/styles/reka-sera/ui/table/utils.tsapps/v4/styles/reka-vega/ui/table/utils.ts
💤 Files with no reviewable changes (13)
- apps/v4/styles/reka-lyra/ui/table/utils.ts
- apps/v4/registry/new-york-v4/ui/_registry.ts
- apps/v4/styles/reka-nova/ui/table/utils.ts
- apps/v4/registry/new-york-v4/ui/table/utils.ts
- apps/v4/lib/utils.ts
- apps/v4/styles/reka-maia/ui/table/utils.ts
- apps/v4/styles/reka-rhea/ui/table/utils.ts
- apps/v4/registry/bases/reka/ui/table/utils.ts
- apps/v4/styles/reka-mira/ui/table/utils.ts
- apps/v4/styles/reka-luma/ui/table/utils.ts
- apps/v4/registry/bases/reka/ui/_registry.ts
- apps/v4/styles/reka-sera/ui/table/utils.ts
- apps/v4/styles/reka-vega/ui/table/utils.ts
Replaces @tanstack/vue-table@8 usage with the v9 API across the demo, tasks and dashboard examples, the dashboard-01 block, and the payments card: - useVueTable -> useTable with explicit tableFeatures(); row models are feature slots and the built-in filter/sort fns are registered (v9 tree-shakes them; unregistered string fns silently no-op) - delete the valueUpdater helper and the table item's utils.ts from the registry (fixes the dead helper on v9); the table item no longer depends on @tanstack/vue-table - drop controlled state refs in favor of v9's internal reactive state; each example keeps one externally managed rowSelection slice to show the pattern - FlexRender :header/:cell shorthand; wrap a bare row.toggleExpanded reference that would lose `this` on v9's prototype methods - rewrite the data-table guide for v9 and update tanstack.com links - regenerate registry output; add the dashboard-01 features.ts to its manifest Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Note GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer. |
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/v4/content/docs/components/data-table.md (1)
226-242: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winConstrain
TDatatoRowData.
ColumnDef<TData>expectsTData extends RowData, but the currentTDatageneric is unconstrained. ImportRowDataand add the constraint to the Vue generic declaration.Proposed fix
-<script setup lang="ts" generic="TData"> -import type { ColumnDef } from '`@tanstack/vue-table`' +<script setup lang="ts" generic="TData extends RowData"> +import type { ColumnDef, RowData } from '`@tanstack/vue-table`'🤖 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 `@apps/v4/content/docs/components/data-table.md` around lines 226 - 242, Update the generic declaration in the data table component to constrain TData to RowData, and import RowData from `@tanstack/vue-table` alongside ColumnDef. Keep the existing props and table logic unchanged.
🤖 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 `@apps/v4/content/docs/components/data-table.md`:
- Around line 681-687: Clarify the header checkbox scope in the columns example
by updating its ariaLabel and the prose around line 701 to state “select all
rows on this page,” matching getIsAllPageRowsSelected() and
toggleAllPageRowsSelected().
- Around line 764-765: Update the table configuration in useTable to provide
getRowCanExpand: () => true, enabling Payment leaf rows to expand and allowing
row.toggleExpanded() to update state; use a row predicate instead if expansion
should be limited to selected rows.
- Around line 425-429: Update the DropdownAction import in the documented
columns.ts example to use the relative path to
components/payments/data-table-dropdown.vue, matching the documented directory
and filename casing.
---
Outside diff comments:
In `@apps/v4/content/docs/components/data-table.md`:
- Around line 226-242: Update the generic declaration in the data table
component to constrain TData to RowData, and import RowData from
`@tanstack/vue-table` alongside ColumnDef. Keep the existing props and table logic
unchanged.
🪄 Autofix
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: bdb53dd1-b821-4be7-be8e-08971e9f81a6
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (55)
apps/v4/components/cards/Payments.vueapps/v4/components/demo/DataTableDemo.vueapps/v4/components/examples/dashboard/components/DataTable.vueapps/v4/components/examples/dashboard/components/DraggableRow.vueapps/v4/components/examples/dashboard/components/features.tsapps/v4/components/examples/tasks/components/DataTable.vueapps/v4/components/examples/tasks/components/DataTableColumnHeader.vueapps/v4/components/examples/tasks/components/DataTableFacetedFilter.vueapps/v4/components/examples/tasks/components/DataTablePagination.vueapps/v4/components/examples/tasks/components/DataTableRowActions.vueapps/v4/components/examples/tasks/components/DataTableToolbar.vueapps/v4/components/examples/tasks/components/DataTableViewOptions.vueapps/v4/components/examples/tasks/components/columns.tsapps/v4/components/examples/tasks/components/features.tsapps/v4/content/docs/03.components-json.mdapps/v4/content/docs/components/data-table.mdapps/v4/lib/utils.tsapps/v4/package.jsonapps/v4/public/r/index.jsonapps/v4/public/r/styles/new-york-v4/dashboard-01.jsonapps/v4/public/r/styles/new-york-v4/registry.jsonapps/v4/public/r/styles/new-york-v4/table.jsonapps/v4/public/r/styles/reka-luma/registry.jsonapps/v4/public/r/styles/reka-luma/table.jsonapps/v4/public/r/styles/reka-lyra/registry.jsonapps/v4/public/r/styles/reka-lyra/table.jsonapps/v4/public/r/styles/reka-maia/registry.jsonapps/v4/public/r/styles/reka-maia/table.jsonapps/v4/public/r/styles/reka-mira/registry.jsonapps/v4/public/r/styles/reka-mira/table.jsonapps/v4/public/r/styles/reka-nova/registry.jsonapps/v4/public/r/styles/reka-nova/table.jsonapps/v4/public/r/styles/reka-rhea/registry.jsonapps/v4/public/r/styles/reka-rhea/table.jsonapps/v4/public/r/styles/reka-sera/registry.jsonapps/v4/public/r/styles/reka-sera/table.jsonapps/v4/public/r/styles/reka-vega/registry.jsonapps/v4/public/r/styles/reka-vega/table.jsonapps/v4/registry/__index__.tsapps/v4/registry/bases/reka/ui/_registry.tsapps/v4/registry/bases/reka/ui/table/utils.tsapps/v4/registry/new-york-v4/blocks/_registry.tsapps/v4/registry/new-york-v4/blocks/dashboard-01/components/DataTable.vueapps/v4/registry/new-york-v4/blocks/dashboard-01/components/DraggableRow.vueapps/v4/registry/new-york-v4/blocks/dashboard-01/components/features.tsapps/v4/registry/new-york-v4/ui/_registry.tsapps/v4/registry/new-york-v4/ui/table/utils.tsapps/v4/styles/reka-luma/ui/table/utils.tsapps/v4/styles/reka-lyra/ui/table/utils.tsapps/v4/styles/reka-maia/ui/table/utils.tsapps/v4/styles/reka-mira/ui/table/utils.tsapps/v4/styles/reka-nova/ui/table/utils.tsapps/v4/styles/reka-rhea/ui/table/utils.tsapps/v4/styles/reka-sera/ui/table/utils.tsapps/v4/styles/reka-vega/ui/table/utils.ts
💤 Files with no reviewable changes (13)
- apps/v4/registry/bases/reka/ui/_registry.ts
- apps/v4/styles/reka-vega/ui/table/utils.ts
- apps/v4/styles/reka-sera/ui/table/utils.ts
- apps/v4/styles/reka-lyra/ui/table/utils.ts
- apps/v4/styles/reka-mira/ui/table/utils.ts
- apps/v4/styles/reka-nova/ui/table/utils.ts
- apps/v4/styles/reka-maia/ui/table/utils.ts
- apps/v4/lib/utils.ts
- apps/v4/styles/reka-rhea/ui/table/utils.ts
- apps/v4/registry/new-york-v4/ui/_registry.ts
- apps/v4/styles/reka-luma/ui/table/utils.ts
- apps/v4/registry/new-york-v4/ui/table/utils.ts
- apps/v4/registry/bases/reka/ui/table/utils.ts
🚧 Files skipped from review as they are similar to previous changes (41)
- apps/v4/public/r/styles/reka-luma/registry.json
- apps/v4/public/r/styles/reka-nova/registry.json
- apps/v4/components/examples/tasks/components/DataTableRowActions.vue
- apps/v4/public/r/styles/reka-rhea/table.json
- apps/v4/public/r/styles/reka-mira/registry.json
- apps/v4/public/r/styles/reka-maia/registry.json
- apps/v4/public/r/styles/reka-lyra/table.json
- apps/v4/components/examples/tasks/components/DataTableColumnHeader.vue
- apps/v4/public/r/styles/reka-lyra/registry.json
- apps/v4/package.json
- apps/v4/public/r/styles/reka-sera/registry.json
- apps/v4/registry/new-york-v4/blocks/dashboard-01/components/DraggableRow.vue
- apps/v4/public/r/styles/new-york-v4/registry.json
- apps/v4/components/demo/DataTableDemo.vue
- apps/v4/content/docs/03.components-json.md
- apps/v4/public/r/styles/reka-vega/registry.json
- apps/v4/public/r/styles/reka-sera/table.json
- apps/v4/components/examples/dashboard/components/DraggableRow.vue
- apps/v4/public/r/styles/reka-vega/table.json
- apps/v4/registry/new-york-v4/blocks/dashboard-01/components/features.ts
- apps/v4/components/examples/tasks/components/DataTableViewOptions.vue
- apps/v4/public/r/styles/reka-rhea/registry.json
- apps/v4/components/examples/tasks/components/DataTablePagination.vue
- apps/v4/components/examples/tasks/components/features.ts
- apps/v4/components/examples/dashboard/components/features.ts
- apps/v4/public/r/styles/reka-luma/table.json
- apps/v4/public/r/index.json
- apps/v4/registry/new-york-v4/blocks/_registry.ts
- apps/v4/public/r/styles/new-york-v4/table.json
- apps/v4/components/examples/tasks/components/DataTable.vue
- apps/v4/public/r/styles/reka-maia/table.json
- apps/v4/registry/index.ts
- apps/v4/public/r/styles/new-york-v4/dashboard-01.json
- apps/v4/components/examples/tasks/components/columns.ts
- apps/v4/components/cards/Payments.vue
- apps/v4/components/examples/tasks/components/DataTableFacetedFilter.vue
- apps/v4/public/r/styles/reka-nova/table.json
- apps/v4/components/examples/dashboard/components/DataTable.vue
- apps/v4/registry/new-york-v4/blocks/dashboard-01/components/DataTable.vue
- apps/v4/public/r/styles/reka-mira/table.json
- apps/v4/components/examples/tasks/components/DataTableToolbar.vue
| Update our columns definition to add a new `actions` column. The `actions` cell returns a `<Dropdown />` component. Because the column doesn't read a data field, we define it with `columnHelper.display`. | ||
|
|
||
| ```ts | ||
| import { ColumnDef } from '@tanstack/vue-table' | ||
| // components/payments/columns.ts | ||
| import DropdownAction from '@/components/DataTableDropDown.vue' |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Fix the DropdownAction import path.
The documented project structure places the file at components/payments/data-table-dropdown.vue, but this import resolves @/components/DataTableDropDown.vue. The directory and filename casing do not match. Use the relative path from components/payments/columns.ts.
Proposed fix
-import DropdownAction from '`@/components/DataTableDropDown.vue`'
+import DropdownAction from './data-table-dropdown.vue'📝 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.
| Update our columns definition to add a new `actions` column. The `actions` cell returns a `<Dropdown />` component. Because the column doesn't read a data field, we define it with `columnHelper.display`. | |
| ```ts | |
| import { ColumnDef } from '@tanstack/vue-table' | |
| // components/payments/columns.ts | |
| import DropdownAction from '@/components/DataTableDropDown.vue' | |
| // components/payments/columns.ts | |
| import DropdownAction from './data-table-dropdown.vue' |
🤖 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 `@apps/v4/content/docs/components/data-table.md` around lines 425 - 429, Update
the DropdownAction import in the documented columns.ts example to use the
relative path to components/payments/data-table-dropdown.vue, matching the
documented directory and filename casing.
| export const columns = columnHelper.columns([ | ||
| columnHelper.display({ | ||
| id: 'select', | ||
| header: ({ table }) => h(Checkbox, { | ||
| 'modelValue': table.getIsAllPageRowsSelected() || (table.getIsSomePageRowsSelected() && 'indeterminate'), | ||
| 'onUpdate:modelValue': (value: boolean | 'indeterminate') => table.toggleAllPageRowsSelected(!!value), | ||
| 'ariaLabel': 'Select all', |
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 'apps/v4/content/docs/components/data-table.md' || true
echo "== relevant lines =="
if [ -f apps/v4/content/docs/components/data-table.md ]; then
nl -ba apps/v4/content/docs/components/data-table.md | sed -n '650,710p'
fi
echo "== search Select all prose/select checkbox context =="
rg -n "Select all rows|Select all|toggleAllPageRowsSelected|getIsAllPageRowsSelected|getIsAllRowsSelected|toggleAllRowsSelected" apps/v4/content/docs/components/data-table.md || trueRepository: unovue/shadcn-vue
Length of output: 280
🌐 Web query:
Tanstack Table Vue migration getIsAllPageRowsSelected toggleAllPageRowsSelected getIsAllRowsSelected toggleAllRowsSele
💡 Result:
In TanStack Table, row selection APIs are consistent across versions v8 and v9 for Vue, though some behavioral details have been clarified [1][2]. These APIs are primarily used to handle "select all" functionality for either all rows in the dataset or only those currently visible on the page [3][4][5]. Key Row Selection APIs The following table instance methods allow you to check the selection status and toggle selection for your header checkboxes [3][4][5]: 1. All Rows (Full Dataset) - Check status: table.getIsAllRowsSelected returns a boolean indicating if all rows are selected [3][4][5]. - Toggle handler: table.getToggleAllRowsSelectedHandler returns a function to bind to your checkbox's change/input event [3][6]. - Manual toggle: table.toggleAllRowsSelected(value: boolean) allows you to programmatically set the selection state [4][5]. 2. Page Rows (Current Page Only) - Check status: table.getIsAllPageRowsSelected returns a boolean indicating if all rows on the current page are selected [7][4][5]. - Toggle handler: table.getToggleAllPageRowsSelectedHandler returns a function to bind to your checkbox's change/input event [7][4][5]. - Manual toggle: table.toggleAllPageRowsSelected(value: boolean) allows you to programmatically set the selection state for the current page [4][5]. Implementation Tip To implement an indeterminate "select all" checkbox, you should bind the checked state to the "all selected" API and the indeterminate state to the "some rows selected" API [3][7][6]. In v9, the "some rows selected" APIs (table.getIsSomeRowsSelected and table.getIsSomePageRowsSelected) were updated to return true when at least one row is selected [1][2]. To maintain the classic indeterminate look, use the following logic for the indeterminate prop [1][2]: table.getIsSomeRowsSelected &&!table.getIsAllRowsSelected [1][2] For further migration details or framework-specific nuances, consult the official TanStack Table migration guides [1][2].
Citations:
- 1: https://tanstack.com/table/latest/docs/framework/vue/guide/migrating
- 2: https://tanstack.com/table/beta/docs/framework/vue/guide/migrating
- 3: https://tanstack.com/table/beta/docs/framework/vue/guide/row-selection
- 4: https://tanstack.com/table/v8/docs/api/features/row-selection
- 5: https://github.com/tanstack/table/blob/main/docs/api/features/row-selection.md
- 6: https://tanstack.com/table/v8/docs/guide/row-selection
- 7: https://tanstack.com/table/beta/docs/framework/vue/examples/row-selection
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== relevant lines =="
awk '{ printf "%6d:%s\n", NR, $0 }' apps/v4/content/docs/components/data-table.md | sed -n '650,715p'
echo "== all select-all/page selection occurrences in file =="
awk '{ printf "%6d:%s\n", NR, $0 }' apps/v4/content/docs/components/data-table.md | rg -n "Select all|toggleAllPageRowsSelected|getIsAllPageRowsSelected|toggleAllRowsSelected|getIsAllRowsSelected" || true
echo "== package versions for Tanstack table if present =="
git ls-files | rg '(^|/)package\.json$|pnpm-lock\.yaml|yarn\.lock|package-lock\.json' | while read -r f; do
if rg -q "`@tanstack`|tanstack" "$f"; then
echo "-- $f --"
rg -n '"`@tanstack/table-core`"|"`@tanstack/vue-table`"|"`@tanstack/table`"|table-core|vue-table' "$f" || true
fi
doneRepository: unovue/shadcn-vue
Length of output: 4149
Clarify the header checkbox scope.
getIsAllPageRowsSelected() and toggleAllPageRowsSelected() apply to the current page only. Update the label and line 701 prose to say “select all rows on this page,” or use the full-dataset APIs if the documentation should cover dataset-wide 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 `@apps/v4/content/docs/components/data-table.md` around lines 681 - 687,
Clarify the header checkbox scope in the columns example by updating its
ariaLabel and the prose around line 701 to state “select all rows on this page,”
matching getIsAllPageRowsSelected() and toggleAllPageRowsSelected().
| Let's make rows expandable. The `rowExpandingFeature` and expanded row model are already registered in our features object, so the table tracks expanded state for us — we just add the UI. | ||
|
|
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
rg -n -C 4 \
'getRowCanExpand|row.toggleExpanded|rowExpandingFeature' \
apps/v4/content/docs/components/data-table.mdRepository: unovue/shadcn-vue
Length of output: 1239
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
# Inspect the relevant DataTable documentation around data model registration, filtering, and expansion.
sed -n '1,210p' apps/v4/content/docs/components/data-table.md
printf '\n--- Expanding section ---\n'
sed -n '700,890p' apps/v4/content/docs/components/data-table.md
# Find concrete Payment/subRows/getRowCanExpand definitions/usages in the docs source.
printf '\n--- broader search ---\n'
rg -n -C 3 'interface Payment|type Payment|subRows|getRowCanExpand|canExpand|toggleExpanded|createExpandedRowModel|rowExpandingFeature' apps/v4/content/docs/components/data-table.mdRepository: unovue/shadcn-vue
Length of output: 13908
🌐 Web query:
TanStack Table v9 getRowCanExpand default subRows false enabledByDefault
💡 Result:
In TanStack Table, the default behavior for row expansion is governed by the presence of sub-rows. Specifically, the row.getCanExpand method returns false by default unless the row contains sub-rows (as determined by your getSubRows configuration) [1][2][3][4]. To customize or override this default behavior, you can provide a custom getRowCanExpand function in your table instance options [1][5][6]. Key points regarding this behavior: 1. Default Logic: By default, a row is only considered "expandable" if it has sub-rows [1][7][8]. 2. Overriding: Providing a getRowCanExpand(row) => boolean function in the table options allows you to force rows to be expandable, even if they lack inherent sub-rows (e.g., when implementing custom expanded UI for rows that do not share the same column structure) [1][2][8]. 3. Configuration: Ensure you have included the necessary expansion features (such as getExpandedRowModel) in your table instance to support this functionality [1][7][4]. Example implementation: const table = useReactTable({ //... other options getRowCanExpand: (row) => true, // Forces all rows to be expandable getCoreRowModel: getCoreRowModel, getExpandedRowModel: getExpandedRowModel, })
Citations:
- 1: https://tanstack.com/table/latest/docs/guide/expanding.md
- 2: https://tanstack.com/table/beta/docs/framework/react/guide/expanding
- 3: https://github.com/TanStack/table/blob/alpha/docs/guide/expanding.md
- 4: https://github.com/TanStack/table/blob/02c203af/docs/guide/expanding.md
- 5: https://tanstack.com/table/alpha/docs/reference/index/interfaces/TableOptions_RowExpanding
- 6: https://github.com/tanstack/table/blob/main/docs/api/features/expanding.md
- 7: https://tanstack.com/table/alpha/docs/guide/expanding
- 8: https://tanstack.com/table/alpha/docs/reference/static-functions/functions/row_getCanExpand
🌐 Web query:
"@tanstack/vue-table" "getRowCanExpand"
💡 Result:
In @tanstack/vue-table, getRowCanExpand is an optional table instance configuration function used to override the default logic for determining if a row can be expanded [1][2][3]. By default, the row instance method row.getCanExpand returns false unless the row contains subRows [1][2]. You can customize this behavior by providing the getRowCanExpand option to your table initialization hook (such as useAppTable or useTable) [4][5][6][3]. Usage example: const table = useAppTable({ //... other options getRowCanExpand: (row) => true, // Allows all rows to be expanded }) When implemented, this function receives the row object as an argument and must return a boolean indicating whether that specific row should be expandable [3]. This is frequently used when implementing custom sub-components where you want to force rows to be expandable regardless of their data structure [4][5][6].
Citations:
- 1: https://tanstack.com/table/beta/docs/framework/vue/guide/expanding
- 2: https://tanstack.com/table/v8/docs/guide/expanding
- 3: https://tanstack.com/table/v8/docs/api/features/expanding
- 4: https://tanstack.com/table/beta/docs/framework/vue/examples/sub-components
- 5: https://tanstack.com/table/alpha/docs/framework/vue/examples/sub-components
- 6: https://github.com/TanStack/table/blob/2a4533e9/examples/vue/sub-components/src/App.vue
Enable expansion for paid leaf rows.
Payment rows do not have subRows, so row.getCanExpand() is false by default and row.toggleExpanded() will not change state. Add getRowCanExpand: () => true to useTable, or use a per-row predicate if only selected rows should expand.
🤖 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 `@apps/v4/content/docs/components/data-table.md` around lines 764 - 765, Update
the table configuration in useTable to provide getRowCanExpand: () => true,
enabling Payment leaf rows to expand and allowing row.toggleExpanded() to update
state; use a row predicate instead if expansion should be limited to selected
rows.
Linked issue
Fixes #1924
Also expected to resolve #1918 — the deselect-all lag comes from v8's coarse re-rendering on selection state changes; v9's fine-grained reactive core (table atoms backed by Vue
computed) is designed to eliminate exactly that. Please verify on the preview deploy.Type of change
Description
Migrates all data-table usage from
@tanstack/vue-table@8to9.0.0(npmlatest):valueUpdateris deleted (the [Feature]: Update table & relevant docs to tanstack table v9 #1924 ask): the registrytableitem'sutils.tsis removed from both registry sources, the 8 generated style copies, andlib/utils.ts; thetableitem no longer depends on@tanstack/vue-table. v9 makes the helper obsolete — state is internal and reactive by default.useVueTable→useTablewith an explicittableFeatures()declaration per table; row models are feature slots (filteredRowModel: createFilteredRowModel(), …); the built-in filter/sort functions are registered explicitly (filterFns: { includesString },sortFns: { alphanumeric, text }) — v9 tree-shakes these, and unregistered string references (including the default'auto') silently no-op.on*Changeupdater dance are gone; tables use v9's internal state, and each example keeps exactly one externally managedrowSelectionslice (ref + state getter + inline updater-resolving handler) to demonstrate the pattern. Reads usetable.atoms.<slice>.get()(reactive in templates; wrapped incomputed()in script).<FlexRender :header="header" />/<FlexRender :cell="cell" />shorthand. One real v9 landmine fixed: a bareonExpand: row.toggleExpandedreference would losethis(v9 methods live on prototypes) — now wrapped.tanstack.com/table/latest/...links); thevalueUpdatermention incomponents-json.mdis updated.public/routput fornew-york-v4+ the 8 reka styles;dashboard-01now ships itsfeatures.ts. Frozen legacy outputs (public/r/styles/{default,new-york}) anddeprecated/untouched.Heads-up for reviewers: many committed
public/r/**/*.jsonfiles show as perpetually modified on any touch because their blobs contain CRLF while.gitattributesmandateseol=lf— a pre-existing repo issue this PR deliberately leaves alone (none of those files are in this diff).Validation
pnpm --filter v4 typecheck— no errors in any touched file (remaining errors are pre-existing ondev, e.g. the dnd-kitPluginDescriptormismatch)pnpm test,pnpm --filter v4 registry:check:iconspnpm registry:buildpnpm --filter v4 build(Nuxt production build)🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Documentation