From 82c1ac136a616ae486c50b873294ddb86bf00300 Mon Sep 17 00:00:00 2001 From: Kevin Van Cott Date: Fri, 5 Jun 2026 13:08:20 -0500 Subject: [PATCH 1/2] feat: drop the underscore. It's cleaner --- _artifacts/domain_map.yaml | 666 +++++++++--------- .../scratch/cluster-a-foundational.yaml | 110 +-- .../scratch/cluster-b-row-model-features.yaml | 120 ++-- .../scratch/cluster-c-ui-state-features.yaml | 28 +- .../scratch/cluster-d-framework-adapters.yaml | 90 +-- .../cluster-e-lifecycle-composition.yaml | 138 ++-- .../cluster-f-issues-failure-modes.yaml | 32 +- _artifacts/skill_spec.md | 8 +- _artifacts/skill_tree.yaml | 68 +- docs/framework/angular/angular-table.md | 30 +- docs/framework/angular/guide/migrating.md | 92 +-- docs/framework/angular/guide/rendering.md | 4 +- .../angular/guide/table-composition.md | 16 +- docs/framework/angular/guide/table-state.md | 26 +- .../reference/functions/createTableHook.md | 4 +- .../reference/functions/injectTable.md | 10 +- .../type-aliases/CreateTableHookResult.md | 2 +- docs/framework/lit/guide/table-state.md | 32 +- docs/framework/lit/lit-table.md | 32 +- .../lit/reference/classes/TableController.md | 8 +- .../reference/functions/createTableHook.md | 6 +- .../preact/guide/create-table-hook.md | 4 +- docs/framework/preact/guide/table-state.md | 40 +- docs/framework/preact/preact-table.md | 30 +- .../reference/functions/createTableHook.md | 6 +- .../preact/reference/functions/useTable.md | 4 +- .../react/guide/create-table-hook.md | 18 +- docs/framework/react/guide/migrating.md | 104 +-- docs/framework/react/guide/table-state.md | 50 +- .../framework/react/guide/use-legacy-table.md | 4 +- docs/framework/react/react-table.md | 30 +- .../index/functions/createTableHook.md | 6 +- .../reference/index/functions/useTable.md | 4 +- .../legacy/functions/useLegacyTable.md | 10 +- .../interfaces/LegacyRowModelOptions.md | 22 +- .../legacy/type-aliases/LegacyTableOptions.md | 6 +- docs/framework/solid/guide/table-state.md | 32 +- .../solid/reference/functions/createTable.md | 4 +- .../reference/functions/createTableHook.md | 6 +- docs/framework/solid/solid-table.md | 30 +- docs/framework/svelte/guide/table-state.md | 32 +- .../svelte/reference/functions/createTable.md | 4 +- .../reference/functions/createTableHook.md | 6 +- docs/framework/svelte/svelte-table.md | 30 +- docs/framework/vanilla/guide/table-state.md | 36 +- docs/framework/vue/guide/table-state.md | 36 +- .../reference/functions/createTableHook.md | 6 +- .../vue/reference/functions/useTable.md | 4 +- docs/framework/vue/vue-table.md | 30 +- docs/guide/column-defs.md | 6 +- docs/guide/column-faceting.md | 12 +- docs/guide/column-filtering.md | 40 +- docs/guide/column-ordering.md | 8 +- docs/guide/column-pinning.md | 10 +- docs/guide/column-resizing.md | 6 +- docs/guide/column-sizing.md | 4 +- docs/guide/column-visibility.md | 10 +- docs/guide/custom-features.md | 18 +- docs/guide/data.md | 10 +- docs/guide/expanding.md | 30 +- docs/guide/features.md | 2 +- docs/guide/fuzzy-filtering.md | 6 +- docs/guide/global-faceting.md | 8 +- docs/guide/global-filtering.md | 34 +- docs/guide/grouping.md | 28 +- docs/guide/pagination.md | 26 +- docs/guide/row-models.md | 20 +- docs/guide/row-selection.md | 10 +- docs/guide/rows.md | 4 +- docs/guide/sorting.md | 54 +- docs/guide/tables.md | 34 +- .../index/functions/createColumnHelper.md | 2 +- .../index/functions/tableFeatures.md | 4 +- .../reference/index/functions/tableOptions.md | 44 +- .../index/interfaces/TableOptions_Core.md | 12 +- .../index/interfaces/TableOptions_Table.md | 8 +- .../index/interfaces/Table_CoreProperties.md | 8 +- .../interfaces/Table_RowModels_Faceted.md | 6 +- .../reference/index/interfaces/Table_Table.md | 12 +- docs/reference/index/type-aliases/Table.md | 2 +- .../index/type-aliases/Table_Internal.md | 8 +- .../functions/table_getCoreRowModel.md | 2 +- .../angular/basic-app-table/src/app/app.ts | 4 +- .../basic-external-atoms/src/app/app.ts | 12 +- .../basic-external-state/src/app/app.ts | 12 +- .../angular/basic-inject-table/src/app/app.ts | 10 +- examples/angular/column-groups/src/app/app.ts | 10 +- .../angular/column-ordering/src/app/app.ts | 6 +- .../column-pinning-split/src/app/app.ts | 10 +- .../column-pinning-sticky/src/app/app.ts | 6 +- .../angular/column-pinning/src/app/app.ts | 6 +- .../column-resizing-performant/src/app/app.ts | 6 +- .../angular/column-resizing/src/app/app.ts | 12 +- examples/angular/column-sizing/src/app/app.ts | 17 +- .../angular/column-visibility/src/app/app.ts | 6 +- .../composable-tables/src/app/table.ts | 4 +- examples/angular/custom-plugin/src/app/app.ts | 10 +- examples/angular/editable/src/app/app.ts | 12 +- examples/angular/expanding/src/app/app.ts | 12 +- .../app/expandable-cell/expandable-cell.ts | 6 +- .../angular/filters-faceted/src/app/app.ts | 6 +- .../src/app/table-filter/table-filter.ts | 6 +- examples/angular/filters-fuzzy/src/app/app.ts | 16 +- examples/angular/filters/src/app/app.ts | 6 +- .../src/app/table-filter/table-filter.ts | 6 +- examples/angular/grouping/src/app/columns.ts | 4 +- examples/angular/kitchen-sink/src/app/app.ts | 6 +- .../src/app/table-filter/table-filter.ts | 4 +- examples/angular/pagination/src/app/app.ts | 12 +- examples/angular/remote-data/src/app/app.ts | 8 +- examples/angular/row-dnd/src/app/app.ts | 2 +- examples/angular/row-pinning/src/app/app.ts | 10 +- .../src/app/app.component.ts | 10 +- .../angular/row-selection/src/app/table.ts | 6 +- .../src/app/person-table/person-table.ts | 10 +- examples/angular/sorting/src/app/app.ts | 14 +- .../angular/sub-components/src/app/app.ts | 10 +- .../virtualized-columns/src/app/app.ts | 10 +- .../src/app/app.ts | 10 +- .../angular/virtualized-rows/src/app/app.ts | 10 +- .../angular/with-tanstack-form/src/app/app.ts | 10 +- .../with-tanstack-query/src/app/app.ts | 10 +- examples/lit/basic-app-table/src/main.ts | 4 +- examples/lit/basic-external-atoms/src/main.ts | 10 +- examples/lit/basic-external-state/src/main.ts | 10 +- .../lit/basic-table-controller/src/main.ts | 12 +- examples/lit/column-groups/src/main.ts | 10 +- examples/lit/column-ordering/src/main.ts | 10 +- examples/lit/column-pinning-split/src/main.ts | 10 +- .../lit/column-pinning-sticky/src/main.ts | 12 +- examples/lit/column-pinning/src/main.ts | 10 +- .../column-resizing-performant/src/main.ts | 10 +- examples/lit/column-resizing/src/main.ts | 10 +- examples/lit/column-sizing/src/main.ts | 10 +- examples/lit/column-visibility/src/main.ts | 10 +- .../src/components/users-table.ts | 2 +- .../lit/composable-tables/src/hooks/table.ts | 4 +- examples/lit/expanding/src/main.ts | 14 +- examples/lit/filters-faceted/src/main.ts | 14 +- examples/lit/filters-fuzzy/src/main.ts | 18 +- examples/lit/filters/src/main.ts | 12 +- examples/lit/grouping/src/main.ts | 17 +- examples/lit/kitchen-sink/src/main.ts | 4 +- examples/lit/pagination/src/main.ts | 10 +- examples/lit/row-pinning/src/main.ts | 18 +- examples/lit/row-selection/src/main.ts | 10 +- examples/lit/sorting-dynamic-data/src/main.ts | 12 +- examples/lit/sorting/src/main.ts | 10 +- examples/lit/sub-components/src/main.ts | 12 +- examples/lit/virtualized-columns/src/main.ts | 10 +- .../src/main.ts | 10 +- examples/lit/virtualized-rows/src/main.ts | 10 +- .../preact/basic-external-atoms/src/main.tsx | 8 +- .../preact/basic-external-state/src/main.tsx | 8 +- examples/preact/basic-subscribe/src/main.tsx | 12 +- .../preact/basic-use-app-table/src/main.tsx | 4 +- examples/preact/basic-use-table/src/main.tsx | 10 +- examples/preact/column-groups/src/main.tsx | 8 +- examples/preact/column-ordering/src/main.tsx | 8 +- .../preact/column-pinning-split/src/main.tsx | 8 +- .../preact/column-pinning-sticky/src/main.tsx | 10 +- examples/preact/column-pinning/src/main.tsx | 4 +- .../column-resizing-performant/src/main.tsx | 10 +- examples/preact/column-resizing/src/main.tsx | 8 +- examples/preact/column-sizing/src/main.tsx | 8 +- .../preact/column-visibility/src/main.tsx | 8 +- .../composable-tables/src/hooks/table.ts | 4 +- .../preact/composable-tables/src/main.tsx | 2 +- examples/preact/custom-plugin/src/main.tsx | 12 +- examples/preact/expanding/src/main.tsx | 12 +- examples/preact/filters-faceted/src/main.tsx | 10 +- examples/preact/filters-fuzzy/src/main.tsx | 18 +- examples/preact/filters/src/main.tsx | 10 +- examples/preact/grouping/src/main.tsx | 4 +- examples/preact/kitchen-sink/src/main.tsx | 4 +- examples/preact/pagination/src/main.tsx | 8 +- examples/preact/row-pinning/src/main.tsx | 16 +- examples/preact/row-selection/src/main.tsx | 12 +- examples/preact/sorting/src/main.tsx | 8 +- examples/preact/sub-components/src/main.tsx | 16 +- .../preact/with-tanstack-query/src/main.tsx | 8 +- .../react/basic-external-atoms/src/main.tsx | 8 +- .../react/basic-external-state/src/main.tsx | 8 +- examples/react/basic-subscribe/src/main.tsx | 12 +- .../react/basic-use-app-table/src/main.tsx | 4 +- .../react/basic-use-legacy-table/src/main.tsx | 12 +- examples/react/basic-use-table/src/main.tsx | 10 +- examples/react/column-dnd/src/main.tsx | 4 +- examples/react/column-groups/src/main.tsx | 8 +- examples/react/column-ordering/src/main.tsx | 8 +- .../react/column-pinning-split/src/main.tsx | 8 +- .../react/column-pinning-sticky/src/main.tsx | 10 +- examples/react/column-pinning/src/main.tsx | 4 +- .../column-resizing-performant/src/main.tsx | 10 +- examples/react/column-resizing/src/main.tsx | 8 +- examples/react/column-sizing/src/main.tsx | 8 +- examples/react/column-visibility/src/main.tsx | 8 +- examples/react/composable-tables/README.md | 4 +- .../composable-tables/src/hooks/table.ts | 4 +- examples/react/composable-tables/src/main.tsx | 2 +- examples/react/custom-plugin/src/main.tsx | 12 +- examples/react/expanding/src/main.tsx | 12 +- examples/react/filters-faceted/src/main.tsx | 10 +- examples/react/filters-fuzzy/src/main.tsx | 18 +- examples/react/filters/src/main.tsx | 10 +- examples/react/grouping/src/main.tsx | 4 +- .../react/kitchen-sink-hero-ui/src/main.tsx | 16 +- .../react/kitchen-sink-mantine/src/main.tsx | 16 +- .../kitchen-sink-material-ui/src/main.tsx | 16 +- .../kitchen-sink-react-aria/src/main.tsx | 16 +- .../kitchen-sink-shadcn-base/src/main.tsx | 10 +- .../kitchen-sink-shadcn-radix/src/main.tsx | 10 +- examples/react/kitchen-sink/src/main.tsx | 4 +- examples/react/lib-hero-ui/src/main.tsx | 8 +- examples/react/lib-mantine/src/main.tsx | 8 +- examples/react/lib-material-ui/src/main.tsx | 8 +- examples/react/lib-react-aria/src/main.tsx | 8 +- examples/react/lib-shadcn-base/src/main.tsx | 10 +- examples/react/lib-shadcn-radix/src/main.tsx | 10 +- examples/react/mantine-react-table/README.md | 2 +- .../hooks/useMRT_TableOptions.ts | 4 +- examples/react/material-react-table/README.md | 2 +- .../hooks/useMRT_TableOptions.ts | 4 +- examples/react/pagination/src/main.tsx | 8 +- examples/react/row-dnd/src/main.tsx | 4 +- examples/react/row-pinning/src/main.tsx | 16 +- examples/react/row-selection/src/main.tsx | 12 +- examples/react/sorting/src/main.tsx | 8 +- examples/react/sub-components/src/main.tsx | 16 +- .../src/main.tsx | 22 +- .../react/virtualized-columns/src/main.tsx | 4 +- .../src/main.tsx | 8 +- .../src/main.tsx | 14 +- examples/react/virtualized-rows/src/main.tsx | 4 +- .../react/with-tanstack-form/src/main.tsx | 12 +- .../react/with-tanstack-query/src/main.tsx | 8 +- .../src/components/table.tsx | 8 +- examples/solid/basic-app-table/src/App.tsx | 4 +- .../solid/basic-external-atoms/src/App.tsx | 8 +- .../solid/basic-external-state/src/App.tsx | 8 +- examples/solid/basic-use-table/src/App.tsx | 10 +- examples/solid/column-groups/src/App.tsx | 6 +- examples/solid/column-ordering/src/App.tsx | 6 +- .../solid/column-pinning-split/src/App.tsx | 8 +- .../solid/column-pinning-sticky/src/App.tsx | 8 +- examples/solid/column-pinning/src/App.tsx | 4 +- .../column-resizing-performant/src/App.tsx | 10 +- examples/solid/column-resizing/src/App.tsx | 8 +- examples/solid/column-sizing/src/App.tsx | 8 +- examples/solid/column-visibility/src/App.tsx | 6 +- examples/solid/composable-tables/src/App.tsx | 2 +- .../composable-tables/src/hooks/table.ts | 4 +- examples/solid/expanding/src/App.tsx | 12 +- examples/solid/filters-faceted/src/App.tsx | 8 +- .../filters-faceted/src/ColumnFilter.tsx | 6 +- examples/solid/filters-fuzzy/src/App.tsx | 18 +- examples/solid/filters/src/App.tsx | 8 +- examples/solid/filters/src/ColumnFilter.tsx | 6 +- examples/solid/grouping/src/App.tsx | 4 +- examples/solid/kitchen-sink/src/App.tsx | 4 +- examples/solid/pagination/src/App.tsx | 8 +- examples/solid/row-pinning/src/App.tsx | 20 +- examples/solid/row-selection/src/App.tsx | 14 +- examples/solid/sorting/src/App.tsx | 8 +- examples/solid/sub-components/src/App.tsx | 16 +- .../solid/virtualized-columns/src/App.tsx | 32 +- .../src/App.tsx | 8 +- examples/solid/virtualized-rows/src/App.tsx | 12 +- examples/solid/with-tanstack-form/src/App.tsx | 12 +- .../solid/with-tanstack-query/src/App.tsx | 8 +- .../src/components/table.tsx | 8 +- .../svelte/basic-app-table/src/App.svelte | 4 +- .../svelte/basic-create-table/src/App.svelte | 10 +- .../basic-external-atoms/src/App.svelte | 8 +- .../basic-external-state/src/App.svelte | 8 +- examples/svelte/basic-snippets/src/App.svelte | 6 +- examples/svelte/column-groups/src/App.svelte | 8 +- .../svelte/column-ordering/src/App.svelte | 8 +- .../column-pinning-split/src/App.svelte | 8 +- .../column-pinning-sticky/src/App.svelte | 8 +- examples/svelte/column-pinning/src/App.svelte | 10 +- .../column-resizing-performant/src/App.svelte | 8 +- .../svelte/column-resizing/src/App.svelte | 8 +- examples/svelte/column-sizing/src/App.svelte | 8 +- .../svelte/column-visibility/src/App.svelte | 8 +- .../src/components/UsersTable.svelte | 2 +- .../composable-tables/src/hooks/table.ts | 4 +- examples/svelte/expanding/src/App.svelte | 10 +- examples/svelte/filtering/src/App.svelte | 8 +- .../svelte/filters-faceted/src/App.svelte | 8 +- examples/svelte/filters-fuzzy/src/App.svelte | 12 +- examples/svelte/grouping/src/App.svelte | 4 +- examples/svelte/kitchen-sink/src/App.svelte | 4 +- examples/svelte/pagination/src/App.svelte | 8 +- examples/svelte/row-pinning/src/App.svelte | 8 +- examples/svelte/row-selection/src/App.svelte | 10 +- examples/svelte/sorting/src/App.svelte | 8 +- .../svelte/sorting/src/tableHelper.svelte.ts | 2 +- examples/svelte/sub-components/src/App.svelte | 12 +- .../svelte/virtualized-columns/src/App.svelte | 6 +- .../src/App.svelte | 8 +- .../svelte/virtualized-rows/src/App.svelte | 8 +- .../svelte/with-tanstack-form/src/App.svelte | 14 +- .../svelte/with-tanstack-query/src/App.svelte | 8 +- examples/vanilla/basic/src/main.ts | 8 +- examples/vanilla/pagination/src/main.ts | 10 +- examples/vanilla/sorting/src/main.ts | 8 +- examples/vue/basic-external-atoms/src/App.tsx | 16 +- examples/vue/basic-external-state/src/App.tsx | 16 +- examples/vue/basic-use-app-table/src/App.vue | 4 +- examples/vue/basic-use-table/src/App.tsx | 20 +- examples/vue/column-groups/src/App.tsx | 18 +- examples/vue/column-ordering/src/App.vue | 12 +- examples/vue/column-pinning-split/src/App.vue | 8 +- .../vue/column-pinning-sticky/src/App.vue | 8 +- examples/vue/column-pinning/src/App.vue | 12 +- .../column-resizing-performant/src/App.vue | 8 +- examples/vue/column-resizing/src/App.vue | 8 +- examples/vue/column-sizing/src/App.vue | 8 +- examples/vue/column-visibility/src/App.tsx | 20 +- .../vue/composable-tables/src/hooks/table.ts | 12 +- examples/vue/expanding/src/App.tsx | 20 +- examples/vue/filters-faceted/src/App.vue | 8 +- examples/vue/filters-fuzzy/src/App.vue | 8 +- examples/vue/filters/src/tableHelper.ts | 4 +- examples/vue/grouping/src/App.vue | 8 +- examples/vue/kitchen-sink/src/App.vue | 4 +- examples/vue/pagination/src/App.vue | 8 +- examples/vue/row-pinning/src/App.vue | 8 +- examples/vue/row-selection/src/App.vue | 8 +- examples/vue/sorting/src/App.vue | 8 +- examples/vue/sub-components/src/App.vue | 4 +- examples/vue/virtualized-columns/src/App.vue | 6 +- .../src/App.vue | 8 +- examples/vue/virtualized-rows/src/App.vue | 8 +- examples/vue/with-tanstack-form/src/App.vue | 8 +- examples/vue/with-tanstack-query/src/App.tsx | 16 +- .../angular-rendering-directives/SKILL.md | 8 +- .../references/content-shapes.md | 4 +- .../create-table-hook-registries.md | 4 +- .../flex-render-component-options.md | 2 +- .../skills/angular/client-to-server/SKILL.md | 22 +- .../compose-with-tanstack-query/SKILL.md | 18 +- .../compose-with-tanstack-store/SKILL.md | 22 +- .../compose-with-tanstack-virtual/SKILL.md | 10 +- .../skills/angular/getting-started/SKILL.md | 78 +- .../references/feature-row-model-mapping.md | 6 +- .../skills/angular/migrate-v8-to-v9/SKILL.md | 50 +- .../references/v8-to-v9-mapping.md | 20 +- .../angular/production-readiness/SKILL.md | 40 +- .../skills/angular/table-state/SKILL.md | 60 +- .../references/external-atoms-and-app-hook.md | 16 +- .../src/helpers/createTableHook.ts | 12 +- packages/angular-table/src/injectTable.ts | 14 +- .../tests/angularReactivityFeature.test.ts | 16 +- .../flex-render/flex-render-table.test.ts | 10 +- .../angular-table/tests/injectTable.test.ts | 8 +- .../compose-with-tanstack-virtual/SKILL.md | 10 +- .../skills/lit/getting-started/SKILL.md | 60 +- .../skills/lit/lit-table-controller/SKILL.md | 32 +- .../skills/lit/migrate-v8-to-v9/SKILL.md | 85 +-- .../lit-table/skills/lit/table-state/SKILL.md | 56 +- packages/lit-table/src/TableController.ts | 12 +- packages/lit-table/src/createTableHook.ts | 8 +- .../tests/unit/defaultReactivity.test.ts | 4 +- .../compose-with-tanstack-devtools/SKILL.md | 4 +- .../skills/preact/client-to-server/SKILL.md | 46 +- .../compose-with-tanstack-form/SKILL.md | 14 +- .../compose-with-tanstack-pacer/SKILL.md | 2 +- .../compose-with-tanstack-query/SKILL.md | 20 +- .../compose-with-tanstack-store/SKILL.md | 10 +- .../compose-with-tanstack-virtual/SKILL.md | 6 +- .../skills/preact/getting-started/SKILL.md | 78 +- .../skills/preact/migrate-v8-to-v9/SKILL.md | 95 +-- .../preact/production-readiness/SKILL.md | 44 +- .../skills/preact/table-state/SKILL.md | 58 +- .../references/advanced-state-patterns.md | 10 +- packages/preact-table/src/createTableHook.tsx | 8 +- packages/preact-table/src/useTable.ts | 8 +- .../compose-with-tanstack-devtools/SKILL.md | 4 +- .../skills/react/client-to-server/SKILL.md | 64 +- .../react/compose-with-tanstack-form/SKILL.md | 22 +- .../compose-with-tanstack-query/SKILL.md | 50 +- .../compose-with-tanstack-store/SKILL.md | 38 +- .../compose-with-tanstack-virtual/SKILL.md | 4 +- ...lumn-virtualization-and-infinite-scroll.md | 12 +- .../skills/react/getting-started/SKILL.md | 90 +-- .../skills/react/migrate-v8-to-v9/SKILL.md | 48 +- .../react/production-readiness/SKILL.md | 50 +- .../skills/react/table-state/SKILL.md | 54 +- packages/react-table/src/createTableHook.tsx | 8 +- packages/react-table/src/useLegacyTable.ts | 44 +- packages/react-table/src/useTable.ts | 8 +- .../compose-with-tanstack-devtools/SKILL.md | 4 +- .../skills/solid/client-to-server/SKILL.md | 12 +- .../solid/compose-with-tanstack-form/SKILL.md | 10 +- .../compose-with-tanstack-pacer/SKILL.md | 14 +- .../compose-with-tanstack-query/SKILL.md | 14 +- .../compose-with-tanstack-store/SKILL.md | 8 +- .../compose-with-tanstack-virtual/SKILL.md | 14 +- .../skills/solid/getting-started/SKILL.md | 36 +- .../skills/solid/migrate-v8-to-v9/SKILL.md | 60 +- .../solid/production-readiness/SKILL.md | 30 +- .../skills/solid/table-state/SKILL.md | 32 +- packages/solid-table/src/createTable.ts | 8 +- packages/solid-table/src/createTableHook.tsx | 8 +- .../skills/svelte/client-to-server/SKILL.md | 12 +- .../compose-with-tanstack-form/SKILL.md | 8 +- .../compose-with-tanstack-pacer/SKILL.md | 2 +- .../compose-with-tanstack-query/SKILL.md | 14 +- .../compose-with-tanstack-store/SKILL.md | 16 +- .../compose-with-tanstack-virtual/SKILL.md | 10 +- .../skills/svelte/getting-started/SKILL.md | 44 +- .../skills/svelte/migrate-v8-to-v9/SKILL.md | 40 +- .../svelte/production-readiness/SKILL.md | 22 +- .../skills/svelte/table-state/SKILL.md | 36 +- .../svelte-table/src/createTable.svelte.ts | 8 +- .../src/createTableHook.svelte.ts | 8 +- .../skills/column-definitions/SKILL.md | 30 +- .../table-core/skills/column-layout/SKILL.md | 20 +- .../customizing-feature-behavior/SKILL.md | 42 +- packages/table-core/skills/filtering/SKILL.md | 38 +- .../references/faceting-and-fuzzy.md | 24 +- packages/table-core/skills/grouping/SKILL.md | 50 +- .../skills/migrate-v8-to-v9/SKILL.md | 60 +- .../table-core/skills/pagination/SKILL.md | 34 +- .../table-core/skills/row-expanding/SKILL.md | 46 +- .../table-core/skills/row-pinning/SKILL.md | 24 +- .../table-core/skills/row-selection/SKILL.md | 30 +- packages/table-core/skills/setup/SKILL.md | 108 +-- packages/table-core/skills/sorting/SKILL.md | 24 +- .../skills/state-management/SKILL.md | 60 +- .../row-models/coreRowModelsFeature.utils.ts | 14 +- .../src/core/table/constructTable.ts | 6 +- .../src/core/table/coreTablesFeature.types.ts | 4 +- .../src/core/table/coreTablesFeature.utils.ts | 6 +- .../columnFacetingFeature.types.ts | 6 +- .../columnFacetingFeature.utils.ts | 12 +- .../table-core/src/helpers/columnHelper.ts | 2 +- .../table-core/src/helpers/tableFeatures.ts | 4 +- .../table-core/src/helpers/tableOptions.ts | 44 +- .../src/store-reactivity-bindings.ts | 2 +- packages/table-core/src/types/Table.ts | 4 +- .../tests/declaration-emit/tableOptions.ts | 16 +- .../tests/helpers/generateTestRows.ts | 10 +- .../tests/helpers/generateTestTable.ts | 20 +- .../tests/helpers/rowPinningHelpers.ts | 20 +- .../row-pinning/rowPinningFeature.test.ts | 14 +- .../row-selection/rowSelectionFeature.test.ts | 84 +-- .../columnGroupingFeature.test.ts | 4 +- .../unit/core/columns/constructColumn.test.ts | 2 +- .../tests/unit/core/rows/constructRow.test.ts | 2 +- .../unit/core/table/constructTable.test.ts | 2 +- .../table/stockFeaturesInitialState.test.ts | 2 +- .../tests/unit/core/tableAtoms.test.ts | 10 +- .../columnPinningFeature.utils.test.ts | 6 +- .../columnSizingFeature.utils.test.ts | 6 +- .../columnVisibilityFeature.utils.test.ts | 48 +- .../tests/unit/fns/filterFns.test.ts | 4 +- .../src/components/FeaturesPanel.tsx | 4 +- .../src/components/OptionsPanel.tsx | 4 +- .../table-devtools/tests/tableTarget.test.ts | 2 +- .../compose-with-tanstack-devtools/SKILL.md | 4 +- .../skills/vue/client-to-server/SKILL.md | 60 +- .../vue/compose-with-tanstack-form/SKILL.md | 18 +- .../vue/compose-with-tanstack-pacer/SKILL.md | 10 +- .../vue/compose-with-tanstack-query/SKILL.md | 28 +- .../vue/compose-with-tanstack-store/SKILL.md | 16 +- .../compose-with-tanstack-virtual/SKILL.md | 10 +- .../skills/vue/getting-started/SKILL.md | 78 +- .../skills/vue/migrate-v8-to-v9/SKILL.md | 56 +- .../skills/vue/production-readiness/SKILL.md | 34 +- .../vue-table/skills/vue/table-state/SKILL.md | 60 +- packages/vue-table/src/createTableHook.ts | 8 +- packages/vue-table/src/useTable.ts | 8 +- 475 files changed, 4156 insertions(+), 4166 deletions(-) diff --git a/_artifacts/domain_map.yaml b/_artifacts/domain_map.yaml index 3e82b8c9db..f127ccc0f3 100644 --- a/_artifacts/domain_map.yaml +++ b/_artifacts/domain_map.yaml @@ -24,7 +24,7 @@ domains: - name: Row-model features slug: row-model-features description: - Features driven by entries in `_rowModels` — filtering (column+global+faceting+fuzzy), + Features driven by entries in `rowModels` — filtering (column+global+faceting+fuzzy), sorting, pagination, grouping, expanding. All have `manual` opt-outs for server-side data. - name: UI-state features slug: ui-state-features @@ -52,15 +52,15 @@ skills: slug: setup domain: core-foundations description: - Install a table adapter and wire up a first working table with `_features`, `_rowModels`, + Install a table adapter and wire up a first working table with `features`, `rowModels`, columns, and data. type: core packages: - '@tanstack/table-core' covers: - tableFeatures - - _features - - _rowModels + - features + - rowModels - useTable - constructTable - _createTable @@ -80,10 +80,10 @@ skills: - Use `@tanstack/table-core` + `storeReactivityBindings()` directly (vanilla JS) when no framework adapter exists failure_modes: - - mistake: Omits `_features` and `_rowModels` + - mistake: Omits `features` and `rowModels` mechanism: - v9 requires `_features` (and an `_rowModels` map, even if empty) at the top of `useTable`/`constructTable` - options. Without `_features`, TypeScript loses feature-state inference and runtime construction + v9 requires `features` (and an `rowModels` map, even if empty) at the top of `useTable`/`constructTable` + options. Without `features`, TypeScript loses feature-state inference and runtime construction has no feature plugins to register. wrong_pattern: | // v8-flavoured, breaks in v9 @@ -94,10 +94,10 @@ skills: }) correct_pattern: | // v9 minimal table - const _features = tableFeatures({}) // empty = core features only + const features = tableFeatures({}) // empty = core features only const table = useTable({ - _features, - _rowModels: {}, // core row model auto-included + features, + rowModels: {}, // core row model auto-included columns, data, }) @@ -109,28 +109,28 @@ skills: → `useTable`) AND new required options were introduced - mistake: Calls `tableFeatures({})` inside the component body mechanism: - A fresh `_features` object on each render destroys the table's stable reference for feature - registration, the same way unstable `columns`/`data` cause infinite re-renders. `_features` must + A fresh `features` object on each render destroys the table's stable reference for feature + registration, the same way unstable `columns`/`data` cause infinite re-renders. `features` must be hoisted to module scope or memoized. wrong_pattern: | function MyTable() { // ❌ new object every render -> potential re-construct + state churn - const _features = tableFeatures({ rowSortingFeature }) - const table = useTable({ _features, _rowModels: {}, columns, data }) + const features = tableFeatures({ rowSortingFeature }) + const table = useTable({ features, rowModels: {}, columns, data }) } correct_pattern: | // ✅ module-scoped, stable reference - const _features = tableFeatures({ rowSortingFeature }) + const features = tableFeatures({ rowSortingFeature }) function MyTable() { - const table = useTable({ _features, _rowModels: {}, columns, data }) + const table = useTable({ features, rowModels: {}, columns, data }) } source: docs/guide/data.md:184-244; examples/react/basic-use-table/src/main.tsx:56 (defined outside component) priority: HIGH status: active - version_context: v9 alpha; new in v9 because v8 had no `_features` option + version_context: v9 alpha; new in v9 because v8 had no `features` option skills: - state-management - mistake: Reaches for `stockFeatures` by default @@ -142,8 +142,8 @@ skills: // ❌ ships every feature, even unused ones import { useTable, stockFeatures } from '@tanstack/react-table' const table = useTable({ - _features: stockFeatures, - _rowModels: {}, + features: stockFeatures, + rowModels: {}, columns, data, }) @@ -156,7 +156,7 @@ skills: rowPaginationFeature, } from '@tanstack/react-table' - const _features = tableFeatures({ + const features = tableFeatures({ rowSortingFeature, rowPaginationFeature, }) @@ -167,15 +167,15 @@ skills: - mistake: Adds a row model without registering its feature mechanism: Row model factories like `createSortedRowModel` only run if the matching feature (e.g. - `rowSortingFeature`) is also registered in `_features`. TypeScript flags this when state slices/APIs + `rowSortingFeature`) is also registered in `features`. TypeScript flags this when state slices/APIs are accessed, but runtime silently degrades — `table.atoms.sorting` is undefined and sort handlers do nothing. wrong_pattern: | - // ❌ rowSortingFeature missing from _features — sortedRowModel orphaned - const _features = tableFeatures({ rowPaginationFeature }) + // ❌ rowSortingFeature missing from features — sortedRowModel orphaned + const features = tableFeatures({ rowPaginationFeature }) const table = useTable({ - _features, - _rowModels: { + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns), // no-op paginatedRowModel: createPaginatedRowModel(), }, @@ -184,13 +184,13 @@ skills: }) correct_pattern: | // ✅ feature + row model registered together - const _features = tableFeatures({ + const features = tableFeatures({ rowSortingFeature, rowPaginationFeature, }) const table = useTable({ - _features, - _rowModels: { + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns), paginatedRowModel: createPaginatedRowModel(), }, @@ -200,7 +200,7 @@ skills: source: docs/guide/row-models.md:46-78; examples/react/basic-external-atoms/src/main.tsx:27-30,81-92 priority: HIGH status: active - version_context: v9 alpha; new failure surface since v8 had no _features/feature-row-model pairing + version_context: v9 alpha; new failure surface since v8 had no features/feature-row-model pairing - mistake: Passing empty array literal to data causes infinite rerenders mechanism: | `const data = items ?? []` creates a new `[]` reference on every render. The @@ -287,12 +287,12 @@ skills: import { useReactTable, getCoreRowModel } from '@tanstack/react-table' const table = useReactTable({ columns, data, getCoreRowModel: getCoreRowModel() }) correct_pattern: |- - // ✅ v9 pattern — `_features` + `_rowModels` + // ✅ v9 pattern — `features` + `rowModels` import { useTable, tableFeatures, rowSortingFeature, createSortedRowModel, sortFns } from '@tanstack/react-table' - const _features = tableFeatures({ rowSortingFeature }) + const features = tableFeatures({ rowSortingFeature }) const table = useTable({ - _features, - _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, data, }) priority: CRITICAL @@ -316,8 +316,8 @@ skills: correct_pattern: |- // ✅ Use the built-in APIs — table handles state, reset, multi-sort, etc. const table = useTable({ - _features: tableFeatures({ rowSortingFeature }), - _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features: tableFeatures({ rowSortingFeature }), + rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, data, }) // then: table.setSorting(...), column.toggleSorting(), header.getToggleSortingHandler() @@ -327,23 +327,23 @@ skills: See `setSorting`/`setColumnFilters`/`toggleSelected`/`nextPage`/etc.' source: maintainer interview (Phase 4, 2026-05-17) status: active - - mistake: API or state slice "missing" because the feature was not registered in `_features` + - mistake: API or state slice "missing" because the feature was not registered in `features` mechanism: - In v9, `_features` is a tree-shakeable registry. If a feature is not in `_features`, TypeScript + In v9, `features` is a tree-shakeable registry. If a feature is not in `features`, TypeScript hides its APIs and the runtime atom is not created. Agents who copy a snippet for `table.setColumnFilters(...)` without registering `columnFilteringFeature` see a TS error or `table.atoms.columnFilters` is undefined — and may incorrectly conclude the feature is broken or removed in v9. wrong_pattern: |- // ❌ rowSortingFeature missing — table.setSorting / state.sorting unavailable - const _features = tableFeatures({}) // empty - const table = useTable({ _features, _rowModels: {}, columns, data }) + const features = tableFeatures({}) // empty + const table = useTable({ features, rowModels: {}, columns, data }) table.setSorting([{ id: 'age', desc: true }]) // ❌ does not exist on this table type correct_pattern: |- // ✅ Register every feature you intend to use; pair with its row model when applicable - const _features = tableFeatures({ rowSortingFeature, rowPaginationFeature }) + const features = tableFeatures({ rowSortingFeature, rowPaginationFeature }) const table = useTable({ - _features, - _rowModels: { + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns), paginatedRowModel: createPaginatedRowModel(), }, @@ -364,20 +364,20 @@ skills: wrong_pattern: |- // ❌ Pulls in every feature even though only sorting+pagination are used import { stockFeatures, tableFeatures } from '@tanstack/react-table' - const _features = tableFeatures(stockFeatures) + const features = tableFeatures(stockFeatures) correct_pattern: |- // ✅ Register only what this table uses import { tableFeatures, rowSortingFeature, rowPaginationFeature } from '@tanstack/react-table' - const _features = tableFeatures({ rowSortingFeature, rowPaginationFeature }) + const features = tableFeatures({ rowSortingFeature, rowPaginationFeature }) priority: HIGH - version_context: v9. Tree-shaking via `_features` is one of the headline reasons for the rewrite. + version_context: v9. Tree-shaking via `features` is one of the headline reasons for the rewrite. source: maintainer interview (Phase 4, 2026-05-17) status: active - name: Column Definitions slug: column-definitions domain: core-foundations description: - Define columns with `createColumnHelper()` to extract data and + Define columns with `createColumnHelper()` to extract data and render headers/cells/footers. type: core packages: @@ -421,9 +421,9 @@ skills: // ❌ v8 signature — TData ends up in the TFeatures slot const columnHelper = createColumnHelper() correct_pattern: | - // ✅ v9 — TFeatures first, TData second; use typeof _features - const _features = tableFeatures({ rowSortingFeature }) - const columnHelper = createColumnHelper() + // ✅ v9 — TFeatures first, TData second; use typeof features + const features = tableFeatures({ rowSortingFeature }) + const columnHelper = createColumnHelper() source: packages/table-core/src/helpers/columnHelper.ts:99-103; docs/framework/react/guide/migrating.md:484-499; examples/react/basic-external-atoms/src/main.tsx:32 @@ -490,7 +490,7 @@ skills: columnHelper.accessor('firstName', { header: 'First' }), columnHelper.accessor('lastName', { header: 'Last' }), ] - const table = useTable({ _features, _rowModels: {}, columns, data }) + const table = useTable({ features, rowModels: {}, columns, data }) } correct_pattern: | // ✅ memoized columns or module-scoped via columnHelper.columns([...]) @@ -503,7 +503,7 @@ skills: ]), [], ) - const table = useTable({ _features, _rowModels: {}, columns, data }) + const table = useTable({ features, rowModels: {}, columns, data }) } source: docs/faq.md:5-128; examples/react/basic-subscribe/src/main.tsx:51-127 priority: CRITICAL @@ -520,8 +520,8 @@ skills: wrong_pattern: | // ❌ no getRowId -> rowSelection survives data updates but maps to wrong rows const table = useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, enableRowSelection: true, @@ -529,8 +529,8 @@ skills: correct_pattern: | // ✅ stable id from the row's own identifier const table = useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, getRowId: (row) => row.id, @@ -667,8 +667,8 @@ skills: correct_pattern: |- // ✅ Use the built-in APIs — table handles state, reset, multi-sort, etc. const table = useTable({ - _features: tableFeatures({ rowSortingFeature }), - _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features: tableFeatures({ rowSortingFeature }), + rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, data, }) // then: table.setSorting(...), column.toggleSorting(), header.getToggleSortingHandler() @@ -745,7 +745,7 @@ skills: const [pagination, setPagination] = React.useState(...) const table = useTable({ - _features, _rowModels: {...}, columns, data, + features, rowModels: {...}, columns, data, state: { pagination }, // ignored onPaginationChange: setPagination, atoms: { pagination: paginationAtom }, // wins @@ -755,7 +755,7 @@ skills: const paginationAtom = useCreateAtom({ pageIndex: 0, pageSize: 10 }) const table = useTable({ - _features, _rowModels: {...}, columns, data, + features, rowModels: {...}, columns, data, atoms: { pagination: paginationAtom }, // no state.pagination, no onPaginationChange needed }) @@ -774,7 +774,7 @@ skills: // ❌ state without callback — sort toggles never reach setSorting const [sorting, setSorting] = React.useState([]) const table = useTable({ - _features, _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features, rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, data, state: { sorting }, // no onSortingChange }) @@ -782,7 +782,7 @@ skills: // ✅ state + on*Change must be paired const [sorting, setSorting] = React.useState([]) const table = useTable({ - _features, _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features, rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, data, state: { sorting }, onSortingChange: setSorting, @@ -800,7 +800,7 @@ skills: // ❌ updates to initialState are ignored after first render function MyTable({ defaultSort }: { defaultSort: SortingState }) { const table = useTable({ - _features, _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features, rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, data, initialState: { sorting: defaultSort }, // ❌ later changes to defaultSort never sync }) @@ -810,7 +810,7 @@ skills: function MyTable({ defaultSort }: { defaultSort: SortingState }) { const [sorting, setSorting] = React.useState(defaultSort) const table = useTable({ - _features, _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features, rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, data, state: { sorting }, onSortingChange: setSorting, @@ -828,7 +828,7 @@ skills: wrong_pattern: | // ❌ direct baseAtoms write while external atom owns the slice const paginationAtom = useCreateAtom({ pageIndex: 0, pageSize: 10 }) - const table = useTable({ _features, _rowModels: {...}, columns, data, atoms: { pagination: paginationAtom } }) + const table = useTable({ features, rowModels: {...}, columns, data, atoms: { pagination: paginationAtom } }) // later, somewhere table.baseAtoms.pagination.set((old) => ({ ...old, pageIndex: 0 })) @@ -853,7 +853,7 @@ skills: // ❌ data is already paginated server-side, but table still slices it const dataQuery = useQuery({ queryKey: ['data', pagination], queryFn: fetchPage }) const table = useTable({ - _features, _rowModels: { paginatedRowModel: createPaginatedRowModel() }, + features, rowModels: { paginatedRowModel: createPaginatedRowModel() }, columns, data: dataQuery.data?.rows ?? [], rowCount: dataQuery.data?.rowCount, @@ -863,7 +863,7 @@ skills: correct_pattern: | // ✅ tell the table the server handles pagination const table = useTable({ - _features, _rowModels: {}, // can drop paginatedRowModel if fully server-side + features, rowModels: {}, // can drop paginatedRowModel if fully server-side columns, data: dataQuery.data?.rows ?? [], rowCount: dataQuery.data?.rowCount, @@ -885,7 +885,7 @@ skills: // ❌ external atom keeps its current value; only baseAtoms reset const sortingAtom = useCreateAtom([]) const table = useTable({ - _features, _rowModels: {...}, columns, data, + features, rowModels: {...}, columns, data, atoms: { sorting: sortingAtom }, }) // ... @@ -916,8 +916,8 @@ skills: correct_pattern: |- // ✅ Use the built-in APIs — table handles state, reset, multi-sort, etc. const table = useTable({ - _features: tableFeatures({ rowSortingFeature }), - _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features: tableFeatures({ rowSortingFeature }), + rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, data, }) // then: table.setSorting(...), column.toggleSorting(), header.getToggleSortingHandler() @@ -927,23 +927,23 @@ skills: See `setSorting`/`setColumnFilters`/`toggleSelected`/`nextPage`/etc.' source: maintainer interview (Phase 4, 2026-05-17) status: active - - mistake: API or state slice "missing" because the feature was not registered in `_features` + - mistake: API or state slice "missing" because the feature was not registered in `features` mechanism: - In v9, `_features` is a tree-shakeable registry. If a feature is not in `_features`, TypeScript + In v9, `features` is a tree-shakeable registry. If a feature is not in `features`, TypeScript hides its APIs and the runtime atom is not created. Agents who copy a snippet for `table.setColumnFilters(...)` without registering `columnFilteringFeature` see a TS error or `table.atoms.columnFilters` is undefined — and may incorrectly conclude the feature is broken or removed in v9. wrong_pattern: |- // ❌ rowSortingFeature missing — table.setSorting / state.sorting unavailable - const _features = tableFeatures({}) // empty - const table = useTable({ _features, _rowModels: {}, columns, data }) + const features = tableFeatures({}) // empty + const table = useTable({ features, rowModels: {}, columns, data }) table.setSorting([{ id: 'age', desc: true }]) // ❌ does not exist on this table type correct_pattern: |- // ✅ Register every feature you intend to use; pair with its row model when applicable - const _features = tableFeatures({ rowSortingFeature, rowPaginationFeature }) + const features = tableFeatures({ rowSortingFeature, rowPaginationFeature }) const table = useTable({ - _features, - _rowModels: { + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns), paginatedRowModel: createPaginatedRowModel(), }, @@ -1009,10 +1009,10 @@ skills: wrong_pattern: | // ❌ "fuzzy" string never registered const table = useTable({ - _features, columns: [ + features, columns: [ columnHelper.accessor('fullName', { filterFn: 'fuzzy' }), ], - _rowModels: { + rowModels: { filteredRowModel: createFilteredRowModel(filterFns), // ❌ no fuzzy in here }, data, @@ -1021,20 +1021,20 @@ skills: // ✅ register the custom fn AND module-augment for type safety declare module '@tanstack/react-table' { interface FilterFns { - fuzzy: FilterFn + fuzzy: FilterFn } } - const fuzzyFilter: FilterFn = (row, columnId, value, addMeta) => { + const fuzzyFilter: FilterFn = (row, columnId, value, addMeta) => { const itemRank = rankItem(row.getValue(columnId), value) addMeta?.({ itemRank }) return itemRank.passed } const table = useTable({ - _features, + features, columns: [columnHelper.accessor('fullName', { filterFn: 'fuzzy' })], - _rowModels: { + rowModels: { filteredRowModel: createFilteredRowModel({ ...filterFns, fuzzy: fuzzyFilter }), }, data, @@ -1071,14 +1071,14 @@ skills: pattern only works when both reference the same column.' wrong_pattern: | // ❌ filter on 'fullName', sort reads meta from 'firstName' - const fuzzySort: SortFn = (a, b, columnId) => { + const fuzzySort: SortFn = (a, b, columnId) => { const meta = a.columnFiltersMeta['firstName'] // ❌ wrong key return meta ? compareItems(meta.itemRank, b.columnFiltersMeta['firstName'].itemRank) : 0 } columnHelper.accessor('fullName', { filterFn: 'fuzzy', sortFn: fuzzySort }) correct_pattern: | // ✅ sortFn uses the same columnId arg that the row's filterFn ran on - const fuzzySort: SortFn = (rowA, rowB, columnId) => { + const fuzzySort: SortFn = (rowA, rowB, columnId) => { let dir = 0 if (rowA.columnFiltersMeta[columnId]) { dir = compareItems( @@ -1212,7 +1212,7 @@ skills: - Implement fuzzy global search with `@tanstack/match-sorter-utils` and a custom `fuzzySort` that reads `row.columnFiltersMeta[columnId].itemRank`. - 'Switch a table to manual server-side filtering: set `manualFiltering: true`, omit the `filteredRowModel` - from `_rowModels`, and pass pre-filtered `data` from the server.' + from `rowModels`, and pass pre-filtered `data` from the server.' - 'Make a tree table filter sub-rows by enabling `filterFromLeafRows: true` so a parent stays visible whenever any child matches.' failure_modes: @@ -1220,12 +1220,12 @@ skills: Forgetting `createFacetedRowModel()` while still registering `createFacetedUniqueValues()` / `createFacetedMinMaxValues()`. mechanism: | - `createFacetedUniqueValues` and `createFacetedMinMaxValues` both compute their results from `column.getFacetedRowModel().flatRows`. Without the base `facetedRowModel` factory in `_rowModels.facetedRowModel`, `column_getFacetedRowModel` falls back to `table.getPreFilteredRowModel()` (see column-faceting/columnFacetingFeature.utils.ts lines 44-56), so facet values are still computed but **don't exclude the column's own active filter** — meaning a select dropdown showing options for a column will collapse to only the currently selected value once the user picks one. + `createFacetedUniqueValues` and `createFacetedMinMaxValues` both compute their results from `column.getFacetedRowModel().flatRows`. Without the base `facetedRowModel` factory in `rowModels.facetedRowModel`, `column_getFacetedRowModel` falls back to `table.getPreFilteredRowModel()` (see column-faceting/columnFacetingFeature.utils.ts lines 44-56), so facet values are still computed but **don't exclude the column's own active filter** — meaning a select dropdown showing options for a column will collapse to only the currently selected value once the user picks one. wrong_pattern: | ```tsx const table = useTable({ - _features: tableFeatures({ columnFacetingFeature, columnFilteringFeature }), - _rowModels: { + features: tableFeatures({ columnFacetingFeature, columnFilteringFeature }), + rowModels: { filteredRowModel: createFilteredRowModel(filterFns), // BUG: missing facetedRowModel - the unique/minMax helpers will use // the pre-filtered model so they include every filter EXCEPT none @@ -1239,12 +1239,12 @@ skills: ```tsx // From examples/react/filters-faceted/src/main.tsx const table = useTable({ - _features: tableFeatures({ + features: tableFeatures({ columnFacetingFeature, columnFilteringFeature, rowPaginationFeature, }), - _rowModels: { + rowModels: { filteredRowModel: createFilteredRowModel(filterFns), paginatedRowModel: createPaginatedRowModel(), facetedRowModel: createFacetedRowModel(), // REQUIRED base @@ -1270,8 +1270,8 @@ skills: // BUG: manualFiltering: true means the filteredRowModel is BYPASSED. // Filter state changes do nothing visible unless `data` is refetched. const table = useTable({ - _features: tableFeatures({ columnFilteringFeature }), - _rowModels: { + features: tableFeatures({ columnFilteringFeature }), + rowModels: { filteredRowModel: createFilteredRowModel(filterFns), }, data, @@ -1288,8 +1288,8 @@ skills: fetch('/api/rows?' + serialize(columnFilters)).then(r => r.json()) ) const table = useTable({ - _features: tableFeatures({ columnFilteringFeature }), - _rowModels: {}, // no filteredRowModel needed for manual filtering + features: tableFeatures({ columnFilteringFeature }), + rowModels: {}, // no filteredRowModel needed for manual filtering data, columns, manualFiltering: true, @@ -1323,19 +1323,19 @@ skills: import { rankItem, compareItems } from '@tanstack/match-sorter-utils' declare module '@tanstack/react-table' { - interface FilterFns { fuzzy: FilterFn } + interface FilterFns { fuzzy: FilterFn } interface FilterMeta { itemRank?: RankingInfo } } - const fuzzyFilter: FilterFn = (row, columnId, value, addMeta) => { + const fuzzyFilter: FilterFn = (row, columnId, value, addMeta) => { const itemRank = rankItem(row.getValue(columnId), value) addMeta?.({ itemRank }) return itemRank.passed } const table = useTable({ - _features, - _rowModels: { + features, + rowModels: { filteredRowModel: createFilteredRowModel({ ...filterFns, // KEEP built-ins fuzzy: fuzzyFilter, // ADD custom @@ -1363,7 +1363,7 @@ skills: const [columnFilters, setColumnFilters] = useState([]) // ^^ empty const table = useTable({ - _features, _rowModels: { filteredRowModel: createFilteredRowModel(filterFns) }, + features, rowModels: { filteredRowModel: createFilteredRowModel(filterFns) }, columns, data, initialState: { columnFilters: [{ id: 'name', value: 'John' }], // IGNORED @@ -1380,7 +1380,7 @@ skills: { id: 'name', value: 'John' }, // seeded here ]) const table = useTable({ - _features, _rowModels: { filteredRowModel: createFilteredRowModel(filterFns) }, + features, rowModels: { filteredRowModel: createFilteredRowModel(filterFns) }, columns, data, state: { columnFilters }, onColumnFiltersChange: setColumnFilters, @@ -1410,8 +1410,8 @@ skills: ```tsx // Override getColumnCanGlobalFilter or set per-column. const table = useTable({ - _features: tableFeatures({ globalFilteringFeature }), - _rowModels: { filteredRowModel: createFilteredRowModel(filterFns) }, + features: tableFeatures({ globalFilteringFeature }), + rowModels: { filteredRowModel: createFilteredRowModel(filterFns) }, columns, data, globalFilterFn: 'includesString', getColumnCanGlobalFilter: (column) => true, // include every column @@ -1436,8 +1436,8 @@ skills: // BUG: filterFromLeafRows hides ALL children that don't match, // even though the parent does match. const table = useTable({ - _features: tableFeatures({ columnFilteringFeature, rowExpandingFeature }), - _rowModels: { filteredRowModel: createFilteredRowModel(filterFns), expandedRowModel: createExpandedRowModel() }, + features: tableFeatures({ columnFilteringFeature, rowExpandingFeature }), + rowModels: { filteredRowModel: createFilteredRowModel(filterFns), expandedRowModel: createExpandedRowModel() }, columns, data, getSubRows: r => r.subRows, filterFromLeafRows: true, @@ -1449,8 +1449,8 @@ skills: ```tsx // Keep parent's whole sub-tree when parent matches: filter root-only. const table = useTable({ - _features: tableFeatures({ columnFilteringFeature, rowExpandingFeature }), - _rowModels: { + features: tableFeatures({ columnFilteringFeature, rowExpandingFeature }), + rowModels: { filteredRowModel: createFilteredRowModel(filterFns), expandedRowModel: createExpandedRowModel(), }, @@ -1538,8 +1538,8 @@ skills: correct_pattern: |- // ✅ Use the built-in APIs — table handles state, reset, multi-sort, etc. const table = useTable({ - _features: tableFeatures({ rowSortingFeature }), - _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features: tableFeatures({ rowSortingFeature }), + rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, data, }) // then: table.setSorting(...), column.toggleSorting(), header.getToggleSortingHandler() @@ -1652,8 +1652,8 @@ skills: }) const table = useTable({ - _features: tableFeatures({ rowSortingFeature }), - _rowModels: { + features: tableFeatures({ rowSortingFeature }), + rowModels: { sortedRowModel: createSortedRowModel({ // pass registry here ...sortFns, myCustom: (a, b, id) => a.original[id] - b.original[id], @@ -1738,7 +1738,7 @@ skills: import { compareItems } from '@tanstack/match-sorter-utils' import { sortFns } from '@tanstack/react-table' - const fuzzySort: SortFn = (rowA, rowB, columnId) => { + const fuzzySort: SortFn = (rowA, rowB, columnId) => { let dir = 0 if (rowA.columnFiltersMeta[columnId]) { dir = compareItems( @@ -1827,8 +1827,8 @@ skills: correct_pattern: |- // ✅ Use the built-in APIs — table handles state, reset, multi-sort, etc. const table = useTable({ - _features: tableFeatures({ rowSortingFeature }), - _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features: tableFeatures({ rowSortingFeature }), + rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, data, }) // then: table.setSorting(...), column.toggleSorting(), header.getToggleSortingHandler() @@ -1903,8 +1903,8 @@ skills: ```tsx // BUG: getPageCount returns 1, next/prev buttons are disabled const table = useTable({ - _features: tableFeatures({ rowPaginationFeature }), - _rowModels: {}, + features: tableFeatures({ rowPaginationFeature }), + rowModels: {}, data, // only 10 rows for the current page columns, manualPagination: true, @@ -1920,8 +1920,8 @@ skills: fetchPage(pagination.pageIndex, pagination.pageSize), ) const table = useTable({ - _features: tableFeatures({ rowPaginationFeature }), - _rowModels: {}, + features: tableFeatures({ rowPaginationFeature }), + rowModels: {}, data: dataQuery.rows, columns, manualPagination: true, @@ -1957,8 +1957,8 @@ skills: // Seed in useState OR use initialState only — never both. const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: 25 }) const table = useTable({ - _features: tableFeatures({ rowPaginationFeature }), - _rowModels: { paginatedRowModel: createPaginatedRowModel() }, + features: tableFeatures({ rowPaginationFeature }), + rowModels: { paginatedRowModel: createPaginatedRowModel() }, columns, data, state: { pagination }, onPaginationChange: setPagination, @@ -1978,7 +1978,7 @@ skills: wrong_pattern: | ```tsx const table = useTable({ - _features, _rowModels: { paginatedRowModel: createPaginatedRowModel(), filteredRowModel: createFilteredRowModel(filterFns) }, + features, rowModels: { paginatedRowModel: createPaginatedRowModel(), filteredRowModel: createFilteredRowModel(filterFns) }, columns, data, autoResetPageIndex: false, // user on page 5, then filters down to 2 pages // -> page 5 is empty. No automatic clamp. @@ -2107,8 +2107,8 @@ skills: correct_pattern: |- // ✅ Use the built-in APIs — table handles state, reset, multi-sort, etc. const table = useTable({ - _features: tableFeatures({ rowSortingFeature }), - _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features: tableFeatures({ rowSortingFeature }), + rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, data, }) // then: table.setSorting(...), column.toggleSorting(), header.getToggleSortingHandler() @@ -2170,10 +2170,10 @@ skills: wrong_pattern: | ```tsx // BUG: grouped rows show aggregates but can't be expanded. - const _features = tableFeatures({ columnGroupingFeature }) + const features = tableFeatures({ columnGroupingFeature }) const table = useTable({ - _features, - _rowModels: { groupedRowModel: createGroupedRowModel(aggregationFns) }, + features, + rowModels: { groupedRowModel: createGroupedRowModel(aggregationFns) }, columns, data, }) // row.getToggleExpandedHandler() -> TS error or undefined @@ -2189,7 +2189,7 @@ skills: rowExpandingFeature, } from '@tanstack/react-table' - const _features = tableFeatures({ + const features = tableFeatures({ columnGroupingFeature, rowExpandingFeature, rowPaginationFeature, @@ -2198,8 +2198,8 @@ skills: }) const table = useTable({ - _features, - _rowModels: { + features, + rowModels: { groupedRowModel: createGroupedRowModel(aggregationFns), expandedRowModel: createExpandedRowModel(), // + sorted, filtered, paginated as needed @@ -2230,8 +2230,8 @@ skills: ```tsx // BUG: v8-style option that doesn't exist in v9 const table = useTable({ - _features: tableFeatures({ columnGroupingFeature }), - _rowModels: { groupedRowModel: createGroupedRowModel(aggregationFns) }, + features: tableFeatures({ columnGroupingFeature }), + rowModels: { groupedRowModel: createGroupedRowModel(aggregationFns) }, columns, data, // @ts-ignore - this property doesn't exist on TableOptions in v9 aggregationFns: { @@ -2245,8 +2245,8 @@ skills: import { aggregationFns, createGroupedRowModel } from '@tanstack/react-table' const table = useTable({ - _features: tableFeatures({ columnGroupingFeature, rowExpandingFeature }), - _rowModels: { + features: tableFeatures({ columnGroupingFeature, rowExpandingFeature }), + rowModels: { groupedRowModel: createGroupedRowModel({ ...aggregationFns, myCustomAggregation: (columnId, leafRows, childRows) => { @@ -2313,8 +2313,8 @@ skills: ```tsx // BUG: column order is overridden by reorder mode const table = useTable({ - _features, - _rowModels: { groupedRowModel: createGroupedRowModel(aggregationFns) }, + features, + rowModels: { groupedRowModel: createGroupedRowModel(aggregationFns) }, columns, data, initialState: { columnOrder: ['firstName', 'lastName', 'age', 'status'], // explicit @@ -2326,8 +2326,8 @@ skills: correct_pattern: | ```tsx const table = useTable({ - _features, - _rowModels: { groupedRowModel: createGroupedRowModel(aggregationFns) }, + features, + rowModels: { groupedRowModel: createGroupedRowModel(aggregationFns) }, columns, data, initialState: { columnOrder: ['firstName', 'lastName', 'age', 'status'], @@ -2387,8 +2387,8 @@ skills: correct_pattern: |- // ✅ Use the built-in APIs — table handles state, reset, multi-sort, etc. const table = useTable({ - _features: tableFeatures({ rowSortingFeature }), - _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features: tableFeatures({ rowSortingFeature }), + rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, data, }) // then: table.setSorting(...), column.toggleSorting(), header.getToggleSortingHandler() @@ -2487,8 +2487,8 @@ skills: // For pure tree data, omit getRowCanExpand and let it auto-detect: // From examples/react/expanding/src/main.tsx const table = useTable({ - _features, - _rowModels: { expandedRowModel: createExpandedRowModel(), /* ... */ }, + features, + rowModels: { expandedRowModel: createExpandedRowModel(), /* ... */ }, columns, data, getSubRows: row => row.subRows, // no getRowCanExpand — row.getCanExpand() is true only when subRows.length > 0 @@ -2497,8 +2497,8 @@ skills: // For pure detail panels, override and skip getSubRows: // From examples/react/sub-components/src/main.tsx const table = useTable({ - _features: tableFeatures({ rowExpandingFeature }), - _rowModels: { expandedRowModel: createExpandedRowModel() }, + features: tableFeatures({ rowExpandingFeature }), + rowModels: { expandedRowModel: createExpandedRowModel() }, columns, data, getRowCanExpand: (row) => true, // every row expands to show }) @@ -2528,8 +2528,8 @@ skills: // From docs/guide/expanding.md // Default behavior (children flow through pagination): const table = useTable({ - _features, - _rowModels: { expandedRowModel: createExpandedRowModel(), paginatedRowModel: createPaginatedRowModel() }, + features, + rowModels: { expandedRowModel: createExpandedRowModel(), paginatedRowModel: createPaginatedRowModel() }, columns, data, getSubRows: r => r.subRows, // paginateExpandedRows defaults to true @@ -2588,8 +2588,8 @@ skills: // BUG: manualExpanding bypasses the expanded row model; // sub-rows are never flattened into view. const table = useTable({ - _features: tableFeatures({ rowExpandingFeature }), - _rowModels: { expandedRowModel: createExpandedRowModel() }, // ignored + features: tableFeatures({ rowExpandingFeature }), + rowModels: { expandedRowModel: createExpandedRowModel() }, // ignored columns, data, getSubRows: r => r.subRows, manualExpanding: true, @@ -2601,8 +2601,8 @@ skills: // returns a pre-flattened view based on which rows are expanded. // From docs/guide/expanding.md const table = useTable({ - _features: tableFeatures({ rowExpandingFeature }), - _rowModels: {}, // no expandedRowModel for manual mode + features: tableFeatures({ rowExpandingFeature }), + rowModels: {}, // no expandedRowModel for manual mode columns, data: dataQuery.data, // server returns flattened rows when expanded manualExpanding: true, @@ -2612,8 +2612,8 @@ skills: // For client-side tree, omit manualExpanding: const table = useTable({ - _features: tableFeatures({ rowExpandingFeature }), - _rowModels: { expandedRowModel: createExpandedRowModel() }, + features: tableFeatures({ rowExpandingFeature }), + rowModels: { expandedRowModel: createExpandedRowModel() }, columns, data, getSubRows: r => r.subRows, }) @@ -2639,8 +2639,8 @@ skills: correct_pattern: |- // ✅ Use the built-in APIs — table handles state, reset, multi-sort, etc. const table = useTable({ - _features: tableFeatures({ rowSortingFeature }), - _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features: tableFeatures({ rowSortingFeature }), + rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, data, }) // then: table.setSorting(...), column.toggleSorting(), header.getToggleSortingHandler() @@ -2788,7 +2788,7 @@ skills: wrong_pattern: | // ❌ Live resize + getSize() on every cell + un-memoized body const table = useTable({ - _features: tableFeatures({ columnSizingFeature, columnResizingFeature }), + features: tableFeatures({ columnSizingFeature, columnResizingFeature }), columnResizeMode: 'onChange', //... }) @@ -2877,14 +2877,14 @@ skills: wrong_pattern: | // ❌ v8 syntax — no longer disables pinning in v9 const table = useTable({ - _features: tableFeatures({ columnPinningFeature }), + features: tableFeatures({ columnPinningFeature }), enablePinning: false, // ignored at table level in v9 //... }) correct_pattern: | // ✅ v9: split into two table-level options const table = useTable({ - _features: tableFeatures({ columnPinningFeature, rowPinningFeature }), + features: tableFeatures({ columnPinningFeature, rowPinningFeature }), enableColumnPinning: false, // turns off column pinning enableRowPinning: false, // turns off row pinning (or row => row.original.locked) //... @@ -3021,7 +3021,7 @@ skills: columnHelper.accessor('lastName', { ... }), ] const table = useTable({ - _features: tableFeatures({ columnPinningFeature, columnResizingFeature }), + features: tableFeatures({ columnPinningFeature, columnResizingFeature }), columns, data, }) @@ -3074,8 +3074,8 @@ skills: correct_pattern: |- // ✅ Use the built-in APIs — table handles state, reset, multi-sort, etc. const table = useTable({ - _features: tableFeatures({ rowSortingFeature }), - _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features: tableFeatures({ rowSortingFeature }), + rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, data, }) // then: table.setSorting(...), column.toggleSorting(), header.getToggleSortingHandler() @@ -3124,14 +3124,14 @@ skills: wrong_pattern: | // ❌ row.id defaults to row.index; pin survives wrong rows after refetch const table = useTable({ - _features: tableFeatures({ rowPinningFeature, rowPaginationFeature }), + features: tableFeatures({ rowPinningFeature, rowPaginationFeature }), data, // refetched periodically //... }) correct_pattern: | // ✅ Stable row identity const table = useTable({ - _features: tableFeatures({ rowPinningFeature, rowPaginationFeature }), + features: tableFeatures({ rowPinningFeature, rowPaginationFeature }), data, getRowId: row => row.userId, // or row.uuid, row.id from API, etc. //... @@ -3156,14 +3156,14 @@ skills: wrong_pattern: | // ❌ Expecting pinned rows to vanish on filter, but they don't (default) const table = useTable({ - _features: tableFeatures({ rowPinningFeature, columnFilteringFeature }), + features: tableFeatures({ rowPinningFeature, columnFilteringFeature }), //... // keepPinnedRows defaults to true; pinned rows survive filtering }) correct_pattern: | // ✅ Be explicit about which UX you want const table = useTable({ - _features: tableFeatures({ rowPinningFeature, columnFilteringFeature }), + features: tableFeatures({ rowPinningFeature, columnFilteringFeature }), keepPinnedRows: false, // pinned rows disappear when filtered/paginated out //... }) @@ -3238,8 +3238,8 @@ skills: correct_pattern: |- // ✅ Use the built-in APIs — table handles state, reset, multi-sort, etc. const table = useTable({ - _features: tableFeatures({ rowSortingFeature }), - _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features: tableFeatures({ rowSortingFeature }), + rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, data, }) // then: table.setSorting(...), column.toggleSorting(), header.getToggleSortingHandler() @@ -3290,7 +3290,7 @@ skills: wrong_pattern: | // ❌ Server-side pagination + default row.id = row.index const table = useTable({ - _features: tableFeatures({ rowSelectionFeature, rowPaginationFeature }), + features: tableFeatures({ rowSelectionFeature, rowPaginationFeature }), data, // only the current page from the server manualPagination: true, rowCount, // server-provided total @@ -3301,7 +3301,7 @@ skills: correct_pattern: | // ✅ Stable row id keyed to the primary key the server uses const table = useTable({ - _features: tableFeatures({ rowSelectionFeature, rowPaginationFeature }), + features: tableFeatures({ rowSelectionFeature, rowPaginationFeature }), data, manualPagination: true, rowCount, @@ -3335,7 +3335,7 @@ skills: wrong_pattern: | // ❌ Checkbox "select all" + single-select mode const table = useTable({ - _features: tableFeatures({ rowSelectionFeature }), + features: tableFeatures({ rowSelectionFeature }), enableMultiRowSelection: false, // radio-like //... }) @@ -3349,7 +3349,7 @@ skills: correct_pattern: | // ✅ Radio inputs, no toggle-all header const table = useTable({ - _features: tableFeatures({ rowSelectionFeature }), + features: tableFeatures({ rowSelectionFeature }), enableMultiRowSelection: false, getRowId: row => row.id, //... @@ -3430,14 +3430,14 @@ skills: // (which is correct for most cases but surprising if you wanted // parent-only selection for a "select this group as a whole" UX) const table = useTable({ - _features: tableFeatures({ rowSelectionFeature, rowExpandingFeature }), + features: tableFeatures({ rowSelectionFeature, rowExpandingFeature }), getSubRows: row => row.subRows, // enableSubRowSelection unset — defaults to true }) correct_pattern: | // ✅ Opt out of parent->child propagation explicitly const table = useTable({ - _features: tableFeatures({ rowSelectionFeature, rowExpandingFeature }), + features: tableFeatures({ rowSelectionFeature, rowExpandingFeature }), getSubRows: row => row.subRows, enableSubRowSelection: false, // toggling parent doesn't touch subRows }) @@ -3534,8 +3534,8 @@ skills: correct_pattern: |- // ✅ Use the built-in APIs — table handles state, reset, multi-sort, etc. const table = useTable({ - _features: tableFeatures({ rowSortingFeature }), - _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features: tableFeatures({ rowSortingFeature }), + rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, data, }) // then: table.setSorting(...), column.toggleSorting(), header.getToggleSortingHandler() @@ -3616,8 +3616,8 @@ skills: external atom, producing surprising divergence. wrong_pattern: | const table = useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, atoms: { pagination: paginationAtom }, @@ -3627,8 +3627,8 @@ skills: correct_pattern: | // Pick exactly one source of truth per slice. const table = useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, atoms: { pagination: paginationAtom }, @@ -3749,8 +3749,8 @@ skills: wrong_pattern: | const pagination = ref({ pageIndex: 0, pageSize: 10 }) const table = useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, state: { pagination }, @@ -3761,8 +3761,8 @@ skills: correct_pattern: | const pagination = ref({ pageIndex: 0, pageSize: 10 }) const table = useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, state: { @@ -3851,16 +3851,16 @@ skills: wrong_pattern: | const [data] = createSignal(makeData(100)) const table = createTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data: data(), }) correct_pattern: | const [data] = createSignal(makeData(100)) const table = createTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, get data() { return data() }, }) @@ -3951,8 +3951,8 @@ skills: wrong_pattern: | let pagination = $state({ pageIndex: 0, pageSize: 10 }) const table = createTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, state: { pagination }, @@ -3963,8 +3963,8 @@ skills: correct_pattern: | let pagination = $state({ pageIndex: 0, pageSize: 10 }) const table = createTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, get data() { return data }, state: { @@ -4026,15 +4026,15 @@ skills: a plain object skips signal tracking and the table never resyncs when source signals update. wrong_pattern: | readonly table = injectTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data: this.data(), }) correct_pattern: | readonly table = injectTable(() => ({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data: this.data(), })) @@ -4112,22 +4112,22 @@ skills: host updates. wrong_pattern: | protected render() { - const tableController = new TableController(this) + const tableController = new TableController(this) const table = tableController.table({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data: this._data, }) return html`...` } correct_pattern: | - private tableController = new TableController(this) + private tableController = new TableController(this) protected render() { const table = this.tableController.table({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data: this._data, }) @@ -4174,7 +4174,7 @@ skills: } correct_pattern: | // wire external atoms through table.atoms or maintain a separate subscription - private tableController = new TableController(this) + private tableController = new TableController(this) private _externalAtom = createAtom({ count: 0 }) private _unsub?: () => void @@ -4218,13 +4218,13 @@ skills: - initialState - createTableHook (createAppColumnHelper, useAppTable, useTableContext, useCellContext, useHeaderContext) tasks: - - Set up useTable in Preact with stable references for data, columns, and _features. + - Set up useTable in Preact with stable references for data, columns, and features. - Optimize a large Preact table by passing () => null as the selector and subscribing lower in the tree. - Build reusable component registries with createTableHook in Preact. failure_modes: - - mistake: Recreating columns or _features on every render + - mistake: Recreating columns or features on every render mechanism: - Preact relies on stable references for table options. New columns or _features arrays each + Preact relies on stable references for table options. New columns or features arrays each render force useTable to call setOptions and rebuild derived state, undoing the work selectors and Subscribe are meant to save. wrong_pattern: | @@ -4232,25 +4232,25 @@ skills: const columns = [ { accessorKey: 'firstName', header: 'First name' }, ] - const _features = tableFeatures({}) + const features = tableFeatures({}) const table = useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, }) return null } correct_pattern: | - const _features = tableFeatures({}) + const features = tableFeatures({}) const columns = [ { accessorKey: 'firstName', header: 'First name' }, ] function App({ data }) { const table = useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, }) @@ -4296,8 +4296,8 @@ skills: setState writes and leaves React-style state stale. wrong_pattern: | const table = useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, atoms: { pagination: paginationAtom }, @@ -4307,8 +4307,8 @@ skills: correct_pattern: | // Pick exactly one source of truth per slice. const table = useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, atoms: { pagination: paginationAtom }, @@ -4502,7 +4502,7 @@ skills: wrong_pattern: | // ❌ Common v9 alpha setup — surfaces SubscribeBound warning on every parent rerender function MyTable({ globalFilter }) { - const table = useTable({ _features, data, columns, state: { globalFilter } }) + const table = useTable({ features, data, columns, state: { globalFilter } }) return ( ({ globalFilter: s.globalFilter })}> {() => ...} @@ -4516,7 +4516,7 @@ skills: function MyTable() { const [globalFilter, setGlobalFilter] = useState('') const table = useTable({ - _features, data, columns, + features, data, columns, state: { globalFilter }, onGlobalFilterChange: setGlobalFilter, }) @@ -4617,9 +4617,9 @@ skills: // ✅ Move to v9 alpha useTable + Subscribe; opt-in subscription model is React-Compiler-friendly 'use client' import { useTable, tableFeatures, rowSelectionFeature } from '@tanstack/react-table' - const _features = tableFeatures({ rowSelectionFeature }) + const features = tableFeatures({ rowSelectionFeature }) export function DataTable({ columns, data }) { - const table = useTable({ _features, data, columns }) + const table = useTable({ features, data, columns }) return ( ({ rowSelection: s.rowSelection })}> {() => } @@ -4650,7 +4650,7 @@ skills: } correct_pattern: | // ✅ Use v9 alpha — table.Subscribe drives re-renders explicitly - const table = useTable({ _features, data, columns }) + const table = useTable({ features, data, columns }) s.rowSelection}> {() => ( @@ -4681,7 +4681,7 @@ skills: ) correct_pattern: |- // ✅ Default useTable selector, inline rendering — Subscribe only when measured perf demands it - const table = useTable({ _features, _rowModels, columns, data }) + const table = useTable({ features, rowModels, columns, data }) // reach for Subscribe later, scoped to the actual hotspot priority: MEDIUM version_context: 'Maintainer guidance: advanced state-management patterns are for advanced cases.' @@ -4924,17 +4924,17 @@ skills: host updates. wrong_pattern: | protected render() { - const controller = new TableController(this) - const table = controller.table({ _features, _rowModels: {}, columns, data: this._data }) + const controller = new TableController(this) + const table = controller.table({ features, rowModels: {}, columns, data: this._data }) return html`...` } correct_pattern: | - private tableController = new TableController(this) + private tableController = new TableController(this) protected render() { const table = this.tableController.table({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data: this._data, }) @@ -5025,14 +5025,14 @@ skills: domain: lifecycle status: ready description: | - End-to-end first-table journey: install the framework adapter, declare `_features` via `tableFeatures()`, declare `_rowModels` factories with their *Fns parameters, create a column helper with both `TFeatures` and `TData` generics, instantiate `useTable` / `injectTable` / `createTable`, and render headers + cells with `table.FlexRender` (or `*flexRender*` directives on Angular). New users land here, not on `useLegacyTable`. + End-to-end first-table journey: install the framework adapter, declare `features` via `tableFeatures()`, declare `rowModels` factories with their *Fns parameters, create a column helper with both `TFeatures` and `TData` generics, instantiate `useTable` / `injectTable` / `createTable`, and render headers + cells with `table.FlexRender` (or `*flexRender*` directives on Angular). New users land here, not on `useLegacyTable`. covers: - Picking the right adapter package (`@tanstack/react-table`, `@tanstack/vue-table`, `@tanstack/angular-table`, `@tanstack/solid-table`, `@tanstack/svelte-table` (Svelte 5+), `@tanstack/preact-table`, `@tanstack/lit-table`). - - 'Declaring the minimum-viable v9 table (no features) — must still pass `_features: tableFeatures({})` - and `_rowModels: {}`. Core row model is automatic; you only register filtered/sorted/paginated/etc. + - 'Declaring the minimum-viable v9 table (no features) — must still pass `features: tableFeatures({})` + and `rowModels: {}`. Core row model is automatic; you only register filtered/sorted/paginated/etc. when you use them.' - - "`createColumnHelper()` and the new `columnHelper.columns([...])` variadic + - "`createColumnHelper()` and the new `columnHelper.columns([...])` variadic wrapper for preserving each column's `TValue` in nested/group columns." - Rendering with `` / `` (preferred) or the standalone `` import. `flexRender(def, ctx)` still works. @@ -5052,10 +5052,10 @@ skills: - '@tanstack/lit-table' tasks: - Render a basic v9 table with 3 columns and an in-memory array. - - 'Add sorting: register `rowSortingFeature` in `_features` and `sortedRowModel: createSortedRowModel(sortFns)` - in `_rowModels`.' + - 'Add sorting: register `rowSortingFeature` in `features` and `sortedRowModel: createSortedRowModel(sortFns)` + in `rowModels`.' - Add pagination + filtering on top of sorting without touching the rest of the setup. - - Type a `ColumnDef[]` array outside the component for stable references. + - Type a `ColumnDef[]` array outside the component for stable references. correct_pattern: | // React — minimum viable v9 table import { @@ -5070,8 +5070,8 @@ skills: type Person = { firstName: string; lastName: string; age: number } // Define OUTSIDE the component for stable identity. - const _features = tableFeatures({ rowSortingFeature }) - const columnHelper = createColumnHelper() + const features = tableFeatures({ rowSortingFeature }) + const columnHelper = createColumnHelper() const columns = columnHelper.columns([ columnHelper.accessor('firstName', { header: 'First' }), @@ -5081,8 +5081,8 @@ skills: function PeopleTable({ data }: { data: Person[] }) { const table = useTable({ - _features, - _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, data, }) @@ -5108,9 +5108,9 @@ skills: // BAD: agents trained on v8 will produce this and it will not compile. // (1) `useReactTable` was removed in favor of `useTable`. // (2) `getCoreRowModel: getCoreRowModel()` is no longer accepted — - // core is implicit; everything else moved to `_rowModels`. + // core is implicit; everything else moved to `rowModels`. // (3) `createColumnHelper()` is missing the TFeatures generic. - // (4) No `_features` => "Property '_features' is missing in type". + // (4) No `features` => "Property 'features' is missing in type". import { useReactTable, getCoreRowModel, createColumnHelper, flexRender } from '@tanstack/react-table' @@ -5121,18 +5121,18 @@ skills: getCoreRowModel: getCoreRowModel(), // removed option }) failure_modes: - - "Forgetting `_features: tableFeatures({})` — the option is required even for a 'no features' table. - Type error: '_features' is missing." - - 'Skipping `_rowModels: {}` — same as above. Core is automatic but the option key itself must be present.' - - Calling `createColumnHelper()` instead of `createColumnHelper()`. + - "Forgetting `features: tableFeatures({})` — the option is required even for a 'no features' table. + Type error: 'features' is missing." + - 'Skipping `rowModels: {}` — same as above. Core is automatic but the option key itself must be present.' + - Calling `createColumnHelper()` instead of `createColumnHelper()`. The generic order changed in v9 and the old shape doesn't compile. - - Defining `_features` / `columns` / `data` literals inside the render body — every render produces + - Defining `features` / `columns` / `data` literals inside the render body — every render produces a new reference and busts table-internal memoization. Always declare these outside the component or wrap in `useMemo`. - Importing `useReactTable` (v8) or `createAngularTable` (v8 Angular) — both were renamed. v9 uses `useTable` / `injectTable` / `createTable` consistently across adapters. - Reaching for `useLegacyTable` for a new project. It's deprecated and ships every feature in the bundle. - New code must use `useTable` with explicit `_features`. + New code must use `useTable` with explicit `features`. - mistake: Reimplementing what TanStack Table's built-in APIs already provide mechanism: TanStack Table IS a state-management coordinator with built-in APIs for nearly every state @@ -5148,8 +5148,8 @@ skills: correct_pattern: |- // ✅ Use the built-in APIs — table handles state, reset, multi-sort, etc. const table = useTable({ - _features: tableFeatures({ rowSortingFeature }), - _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features: tableFeatures({ rowSortingFeature }), + rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, data, }) // then: table.setSorting(...), column.toggleSorting(), header.getToggleSortingHandler() @@ -5159,23 +5159,23 @@ skills: See `setSorting`/`setColumnFilters`/`toggleSelected`/`nextPage`/etc.' source: maintainer interview (Phase 4, 2026-05-17) status: active - - mistake: API or state slice "missing" because the feature was not registered in `_features` + - mistake: API or state slice "missing" because the feature was not registered in `features` mechanism: - In v9, `_features` is a tree-shakeable registry. If a feature is not in `_features`, TypeScript + In v9, `features` is a tree-shakeable registry. If a feature is not in `features`, TypeScript hides its APIs and the runtime atom is not created. Agents who copy a snippet for `table.setColumnFilters(...)` without registering `columnFilteringFeature` see a TS error or `table.atoms.columnFilters` is undefined — and may incorrectly conclude the feature is broken or removed in v9. wrong_pattern: |- // ❌ rowSortingFeature missing — table.setSorting / state.sorting unavailable - const _features = tableFeatures({}) // empty - const table = useTable({ _features, _rowModels: {}, columns, data }) + const features = tableFeatures({}) // empty + const table = useTable({ features, rowModels: {}, columns, data }) table.setSorting([{ id: 'age', desc: true }]) // ❌ does not exist on this table type correct_pattern: |- // ✅ Register every feature you intend to use; pair with its row model when applicable - const _features = tableFeatures({ rowSortingFeature, rowPaginationFeature }) + const features = tableFeatures({ rowSortingFeature, rowPaginationFeature }) const table = useTable({ - _features, - _rowModels: { + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns), paginatedRowModel: createPaginatedRowModel(), }, @@ -5196,9 +5196,9 @@ skills: Mechanical breaking-change migration from TanStack Table v8 to v9 across every adapter. Every old-shaped option, type, or method an agent will try to reproduce from v8 muscle memory has a v9 equivalent enumerated below. For React projects that cannot migrate every table at once, `useLegacyTable` from `@tanstack/react-table/legacy` accepts the v8 API shape on top of the v9 engine — deprecated, ships every feature, no `table.Subscribe`, but lets you upgrade incrementally. covers: - Hook rename per adapter (React, Angular, Solid, Vue, Preact, Svelte 5+, Lit, vanilla). - - '`_features` + `_rowModels` becoming required options; row-model factories now take their *Fns set + - '`features` + `rowModels` becoming required options; row-model factories now take their *Fns set as a parameter.' - - '`createColumnHelper()` → `createColumnHelper()` (generic order + + - '`createColumnHelper()` → `createColumnHelper()` (generic order + arity change).' - 'State surface: `table.getState()` → `table.store.state` (full) or `table.state` (selector output) or `table.atoms..get()`.' @@ -5231,12 +5231,12 @@ skills: - '@tanstack/table-core' tasks: - 'Upgrade a v8 React table to v9 by renaming `useReactTable` → `useTable`, moving `getCoreRowModel`/`getFilteredRowModel`/`getSortedRowModel`/`getPaginationRowModel` - options into `_rowModels`, and adding `_features: tableFeatures({...})`.' + options into `rowModels`, and adding `features: tableFeatures({...})`.' - Bridge a v8 React table to v9 via `useLegacyTable` from `@tanstack/react-table/legacy` so the rest of the app can upgrade incrementally. - Rename `table.getState()` reads throughout the codebase to `table.store.state` (full read) or `table.state` (typed selector output) or `table.atoms..get()` (single-slice atom read). - - Update all `createColumnHelper()` call sites to `createColumnHelper()` + - Update all `createColumnHelper()` call sites to `createColumnHelper()` and adjust `ColumnDef` / `Column` / `Row` / `Cell` type annotations to the new `TFeatures`-first generic order. correct_pattern: | @@ -5258,7 +5258,7 @@ skills: } from '@tanstack/react-table' import type { ColumnDef } from '@tanstack/react-table' - const _features = tableFeatures({ + const features = tableFeatures({ rowSortingFeature, rowPaginationFeature, columnFilteringFeature, @@ -5266,9 +5266,9 @@ skills: columnResizingFeature, // explicit — formerly part of ColumnSizing }) - const columnHelper = createColumnHelper() + const columnHelper = createColumnHelper() - const columns: ColumnDef[] = columnHelper.columns([ + const columns: ColumnDef[] = columnHelper.columns([ columnHelper.accessor('name', { header: 'Name', sortFn: 'alphanumeric', // renamed from sortingFn @@ -5276,8 +5276,8 @@ skills: ]) const table = useTable({ - _features, - _rowModels: { + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns), filteredRowModel: createFilteredRowModel(filterFns), paginatedRowModel: createPaginatedRowModel(), @@ -5303,7 +5303,7 @@ skills: import { useReactTable, // (1) renamed → useTable getCoreRowModel, // (2) no longer accepted as an option; - getFilteredRowModel, // move to `_rowModels` as factories + getFilteredRowModel, // move to `rowModels` as factories getSortedRowModel, // created via `createSortedRowModel(sortFns)` etc. getPaginationRowModel, createColumnHelper, // (3) needs now @@ -5326,7 +5326,7 @@ skills: const table = useReactTable({ columns, data, - getCoreRowModel: getCoreRowModel(), // (2) move into `_rowModels` + getCoreRowModel: getCoreRowModel(), // (2) move into `rowModels` getFilteredRowModel: getFilteredRowModel(), getSortedRowModel: getSortedRowModel(), getPaginationRowModel: getPaginationRowModel(), @@ -5362,14 +5362,14 @@ skills: to `useTable` / `injectTable` / `createTable` in v9. The v8 imports will not exist and will fail at module-resolution time. - 'Passing `getCoreRowModel: getCoreRowModel()` / `getSortedRowModel: getSortedRowModel()` as root options. - These were removed — sortedRowModel/filteredRowModel/etc. now live under `_rowModels` and are produced + These were removed — sortedRowModel/filteredRowModel/etc. now live under `rowModels` and are produced by `createSortedRowModel(sortFns)`-style factories. Core is automatic.' - Calling `createSortedRowModel()` without passing `sortFns`. The factories now REQUIRE their *Fns parameter for tree-shaking — `createFilteredRowModel(filterFns)`, `createSortedRowModel(sortFns)`, `createGroupedRowModel(aggregationFns)`. - - "Omitting `_features` entirely. The option is required even for a no-features table — pass `_features: - tableFeatures({})` or `_features: stockFeatures` if you want v8-like 'everything on'." - - Calling `createColumnHelper()` (v8 arity). v9 requires `createColumnHelper()`. `typeof _features` is the standard idiom — declare features once at module scope and reuse + - "Omitting `features` entirely. The option is required even for a no-features table — pass `features: + tableFeatures({})` or `features: stockFeatures` if you want v8-like 'everything on'." + - Calling `createColumnHelper()` (v8 arity). v9 requires `createColumnHelper()`. `typeof features` is the standard idiom — declare features once at module scope and reuse the type. - Reading state via `table.getState()`. The method was removed. Use `table.store.state` for a flat snapshot, `table.state` if you passed a `useTable` selector, or `table.atoms..get()` for a single slice. @@ -5423,7 +5423,7 @@ skills: mechanism: | v9 alpha renames `useReactTable` → `useTable` (and adds a `useLegacyTable` shim). Agents trained on v8 will reach for `useReactTable`. The signature also changes — - `_features` and `_rowModels` are now mandatory configuration, not pre-bundled + `features` and `rowModels` are now mandatory configuration, not pre-bundled defaults. `useReactTable` still exists for back-compat but produces v8-style tables that don't have `.Subscribe`, `.atoms`, or feature composition. wrong_pattern: | @@ -5439,10 +5439,10 @@ skills: useTable, tableFeatures, sortingFeature, columnFilteringFeature, rowPaginationFeature, } from '@tanstack/react-table' - const _features = tableFeatures({ + const features = tableFeatures({ sortingFeature, columnFilteringFeature, rowPaginationFeature, }) - const table = useTable({ _features, data, columns }) + const table = useTable({ features, data, columns }) source: 'PR #6202 (fix useLegacyTable infinite rerender), useTable.ts source, CHANGELOG history' priority: CRITICAL status: active @@ -5450,29 +5450,29 @@ skills: - mistake: Importing pre-bundled getCoreRowModel etc. in v9 mechanism: | In v8, `getCoreRowModel()`, `getSortedRowModel()`, `getFilteredRowModel()` etc. - were standalone factories. In v9, row models are opt-in through `_rowModels` on + were standalone factories. In v9, row models are opt-in through `rowModels` on the table options or auto-installed by features in `tableFeatures()`. Agents will keep emitting v8 imports that either don't exist or aren't wired correctly. wrong_pattern: | // ❌ v8 pattern — won't drive v9 row models const table = useTable({ - _features, + features, data, columns, getCoreRowModel: getCoreRowModel(), getSortedRowModel: getSortedRowModel(), }) correct_pattern: | - // ✅ v9 — row models opt-in via _rowModels or feature inclusion + // ✅ v9 — row models opt-in via rowModels or feature inclusion import { useTable, tableFeatures, sortingFeature, coreRowModelsFeature, sortedRowModelsFeature, } from '@tanstack/react-table' - const _features = tableFeatures({ + const features = tableFeatures({ sortingFeature, coreRowModelsFeature, sortedRowModelsFeature, }) - const table = useTable({ _features, data, columns }) + const table = useTable({ features, data, columns }) source: 'PR #6234 (atoms refactor), v9 alpha package exports' priority: CRITICAL status: active @@ -5515,12 +5515,12 @@ skills: import { useReactTable, getCoreRowModel } from '@tanstack/react-table' const table = useReactTable({ columns, data, getCoreRowModel: getCoreRowModel() }) correct_pattern: |- - // ✅ v9 pattern — `_features` + `_rowModels` + // ✅ v9 pattern — `features` + `rowModels` import { useTable, tableFeatures, rowSortingFeature, createSortedRowModel, sortFns } from '@tanstack/react-table' - const _features = tableFeatures({ rowSortingFeature }) + const features = tableFeatures({ rowSortingFeature }) const table = useTable({ - _features, - _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, data, }) priority: CRITICAL @@ -5534,11 +5534,11 @@ skills: domain: lifecycle status: ready description: | - Convert a client-side table to server-side (a.k.a. manual modes). Pattern: pass server data, set `manualSorting` / `manualFiltering` / `manualPagination` / `manualGrouping` / `manualExpanding` for whatever the server now owns, supply `rowCount` (and/or `pageCount`) so the table can paginate without seeing all rows, and remove the corresponding `_rowModels` entries (you don't need `paginatedRowModel` if pagination is server-side). State for the server-managed slices is best owned EITHER via external TanStack Store atoms (passed via `options.atoms`) OR via classic `state` + `on*Change` controlled state — both work. With Query, the atom pattern lets you key your query on the atom and let the table write directly to it without `on*Change` plumbing. + Convert a client-side table to server-side (a.k.a. manual modes). Pattern: pass server data, set `manualSorting` / `manualFiltering` / `manualPagination` / `manualGrouping` / `manualExpanding` for whatever the server now owns, supply `rowCount` (and/or `pageCount`) so the table can paginate without seeing all rows, and remove the corresponding `rowModels` entries (you don't need `paginatedRowModel` if pagination is server-side). State for the server-managed slices is best owned EITHER via external TanStack Store atoms (passed via `options.atoms`) OR via classic `state` + `on*Change` controlled state — both work. With Query, the atom pattern lets you key your query on the atom and let the table write directly to it without `on*Change` plumbing. covers: - Setting `manualSorting`, `manualFiltering`, `manualPagination`, `manualGrouping`, `manualExpanding` so the table stops trying to slice rows it doesn't have. - - Removing the matching `_rowModels` keys so unused factories don't ship (don't register `paginatedRowModel` + - Removing the matching `rowModels` keys so unused factories don't ship (don't register `paginatedRowModel` if the server paginates). - Providing `rowCount` (and optionally `pageCount`) so `table.getPageCount()` / `getCanNextPage()` work without local rows. @@ -5572,7 +5572,7 @@ skills: import { useCreateAtom, useSelector } from '@tanstack/react-store' import type { PaginationState } from '@tanstack/react-table' - const _features = tableFeatures({ rowPaginationFeature }) + const features = tableFeatures({ rowPaginationFeature }) function ServerTable({ columns }) { // 1) Own pagination in an external atom. @@ -5592,10 +5592,10 @@ skills: }) // 3) Manual pagination + `rowCount` for getPageCount(). Note: no - // `paginatedRowModel` in `_rowModels` — server paginates. + // `paginatedRowModel` in `rowModels` — server paginates. const table = useTable({ - _features, - _rowModels: {}, // core only + features, + rowModels: {}, // core only columns, data: dataQuery.data?.rows ?? [], rowCount: dataQuery.data?.rowCount, @@ -5610,8 +5610,8 @@ skills: // This makes the table try to slice the (already-sliced) `data` array // a second time, producing rows that don't exist. const table = useTable({ - _features, - _rowModels: { paginatedRowModel: createPaginatedRowModel() }, + features, + rowModels: { paginatedRowModel: createPaginatedRowModel() }, columns, data: serverPage.rows, // missing: manualPagination + rowCount @@ -5621,8 +5621,8 @@ skills: // `Math.ceil(rows.length / pageSize)` which is the page size, not the // total — the pager shows "Page 1 of 1" forever. const table = useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data: serverPage.rows, manualPagination: true, @@ -5639,7 +5639,7 @@ skills: // `state + on*Change`. Don't pass `state` without `on*Change`. const [pagination, setPagination] = useState({...}) useTable({ - _features, _rowModels: {}, columns, data, + features, rowModels: {}, columns, data, state: { pagination }, // missing: onPaginationChange: setPagination manualPagination: true, @@ -5648,7 +5648,7 @@ skills: - 'Forgetting `manualPagination: true` (or `manualSorting` / `manualFiltering`). The table will re-sort/re-filter/re-paginate the already-server-processed rows, producing visually incorrect or duplicated results.' - 'Leaving `paginatedRowModel: createPaginatedRowModel()` registered when the server paginates. The - factory ships in your bundle for no reason AND the table slices server-sliced data. Drop it from `_rowModels`.' + factory ships in your bundle for no reason AND the table slices server-sliced data. Drop it from `rowModels`.' - Omitting `rowCount`. Without it, `getPageCount()` is computed from `data.length / pageSize` — which equals 1 if the server returned a single page. Pager UIs lock at 'Page 1 of 1'. - Passing `state.pagination` without `onPaginationChange`. The library treats `state` as controlled; @@ -5665,11 +5665,11 @@ skills: domain: lifecycle status: ready description: | - Ship-ready optimizations for v9: tree-shake the bundle by registering ONLY the `_features` you actually use; memoize `_features`, `data`, and `columns` for stable identity; replace `(state) => state` with narrow selectors or per-slice `useSelector(table.atoms.)` subscriptions; and push state-driven re-renders down the tree with `` (or the standalone `` import) so the expensive table body doesn't re-render every time you toggle a sort indicator. Production builds of the table devtools are also a `/production` import flip — see `compose-with-tanstack-devtools`. + Ship-ready optimizations for v9: tree-shake the bundle by registering ONLY the `features` you actually use; memoize `features`, `data`, and `columns` for stable identity; replace `(state) => state` with narrow selectors or per-slice `useSelector(table.atoms.)` subscriptions; and push state-driven re-renders down the tree with `` (or the standalone `` import) so the expensive table body doesn't re-render every time you toggle a sort indicator. Production builds of the table devtools are also a `/production` import flip — see `compose-with-tanstack-devtools`. covers: - "Tree-shaking: list features explicitly in `tableFeatures({...})` rather than `stockFeatures`. A sort-only table is ~6–7kb vs ~15–20kb for v8's all-in approach." - - 'Reference stability: `_features`, `_rowModels`, `columns`, and `data` should NOT be redefined on + - 'Reference stability: `features`, `rowModels`, `columns`, and `data` should NOT be redefined on every render. Declare at module scope or memoize with `useMemo` / Angular `signal()` / Solid memo.' - "Default selector trade-off: `(state) => state` matches v8 behavior but forces a re-render on any state change. Narrow it (`(state) => ({ sorting: state.sorting })`) once you've profiled." @@ -5693,7 +5693,7 @@ skills: - '@tanstack/svelte-table' - '@tanstack/preact-table' tasks: - - Audit a project's `_features` declarations and remove any feature whose imports aren't actually wired + - Audit a project's `features` declarations and remove any feature whose imports aren't actually wired up in column defs / state. - Replace `useTable(opts, (state) => state)` with a narrowed selector when only a subset of state is rendered at the table level. @@ -5714,8 +5714,8 @@ skills: } from '@tanstack/react-table' // Module-scope, stable identity: - const _features = tableFeatures({ rowSortingFeature, rowPaginationFeature }) - const _rowModels = { + const features = tableFeatures({ rowSortingFeature, rowPaginationFeature }) + const rowModels = { sortedRowModel: createSortedRowModel(sortFns), paginatedRowModel: createPaginatedRowModel(), } @@ -5723,7 +5723,7 @@ skills: function MyTable({ data, columns }) { // ✓ narrow selector — re-renders only when these slices change const table = useTable( - { _features, _rowModels, columns, data }, + { features, rowModels, columns, data }, (state) => ({ sorting: state.sorting, pagination: state.pagination, @@ -5754,16 +5754,16 @@ skills: // BAD #1: stockFeatures in a sort-only table. // Ships filtering, faceting, grouping, pinning, expanding, sizing, // resizing, visibility, ordering, row-selection, row-pinning code - // none of which is used. ~3x the necessary bundle for `_features`. + // none of which is used. ~3x the necessary bundle for `features`. import { useTable, stockFeatures } from '@tanstack/react-table' - const table = useTable({ _features: stockFeatures, /* ... */ }) + const table = useTable({ features: stockFeatures, /* ... */ }) // BAD #2: unstable references — every render is a new identity. function MyTable({ data, columns }) { - const _features = tableFeatures({ rowSortingFeature }) // new every render + const features = tableFeatures({ rowSortingFeature }) // new every render const opts = { // new every render - _features, - _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, // hopefully stable data, } @@ -5792,7 +5792,7 @@ skills: - Using `stockFeatures` in production without auditing which features are actually rendered. Defeats the whole reason tree-shaking exists in v9. Replace with an explicit `tableFeatures({...})` listing only what your UI uses. - - Declaring `_features`, `_rowModels`, or `columns` inside the component body without `useMemo`. Internal + - Declaring `features`, `rowModels`, or `columns` inside the component body without `useMemo`. Internal memoization keys off identity, so a new object every render forces full recomputation. - Putting `data` in `useState` and never memoizing the array literal that produces it. `setData(rows.filter(...))` returns a new array each call — that's fine; the FAQ pitfall is `data={[]}` or `data={rows ?? []}` @@ -5839,13 +5839,13 @@ skills: wrong_pattern: |- // ❌ Pulls in every feature even though only sorting+pagination are used import { stockFeatures, tableFeatures } from '@tanstack/react-table' - const _features = tableFeatures(stockFeatures) + const features = tableFeatures(stockFeatures) correct_pattern: |- // ✅ Register only what this table uses import { tableFeatures, rowSortingFeature, rowPaginationFeature } from '@tanstack/react-table' - const _features = tableFeatures({ rowSortingFeature, rowPaginationFeature }) + const features = tableFeatures({ rowSortingFeature, rowPaginationFeature }) priority: HIGH - version_context: v9. Tree-shaking via `_features` is one of the headline reasons for the rewrite. + version_context: v9. Tree-shaking via `features` is one of the headline reasons for the rewrite. source: maintainer interview (Phase 4, 2026-05-17) status: active - mistake: Premature Subscribe / custom selector optimization on small tables @@ -5862,7 +5862,7 @@ skills: ) correct_pattern: |- // ✅ Default useTable selector, inline rendering — Subscribe only when measured perf demands it - const table = useTable({ _features, _rowModels, columns, data }) + const table = useTable({ features, rowModels, columns, data }) // reach for Subscribe later, scoped to the actual hotspot priority: MEDIUM version_context: 'Maintainer guidance: advanced state-management patterns are for advanced cases.' @@ -5915,7 +5915,7 @@ skills: } from '@tanstack/react-table' import type { PaginationState, SortingState } from '@tanstack/react-table' - const _features = tableFeatures({ rowSortingFeature, rowPaginationFeature }) + const features = tableFeatures({ rowSortingFeature, rowPaginationFeature }) function MyTable({ columns, data }) { const sortingAtom = useCreateAtom([]) @@ -5928,8 +5928,8 @@ skills: const pagination = useSelector(paginationAtom) const table = useTable({ - _features, - _rowModels: { + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns), paginatedRowModel: createPaginatedRowModel(), }, @@ -5953,7 +5953,7 @@ skills: // BAD #1: passing the SAME slice via both `state` and `atoms`. Atoms // win silently and the `state` value is ignored — confusing to debug. useTable({ - _features, _rowModels: {}, + features, rowModels: {}, columns, data, state: { sorting: localSorting }, // ignored onSortingChange: setLocalSorting, // ignored @@ -5965,7 +5965,7 @@ skills: // resets to initial. (The same trap as `useState(createAtom(...))`.) function MyTable() { const sortingAtom = createAtom([]) // wrong: unstable - useTable({ _features, _rowModels: {}, columns, data, + useTable({ features, rowModels: {}, columns, data, atoms: { sorting: sortingAtom } }) } @@ -6032,7 +6032,7 @@ skills: from '@tanstack/react-table' import type { PaginationState } from '@tanstack/react-table' - const _features = tableFeatures({ rowPaginationFeature }) + const features = tableFeatures({ rowPaginationFeature }) function ServerTable({ columns }) { const paginationAtom = useCreateAtom({ @@ -6047,8 +6047,8 @@ skills: }) const table = useTable({ - _features, - _rowModels: {}, // server paginates + features, + rowModels: {}, // server paginates columns, data: dataQuery.data?.rows ?? EMPTY, // EMPTY is module-scope rowCount: dataQuery.data?.rowCount, @@ -6091,7 +6091,7 @@ skills: inputs changed; clicks on the pager update state but the query never refetches. - 'Skipping `placeholderData: keepPreviousData`. Between pages the table collapses to 0 rows, the row container collapses, and the scroll position jumps.' - - 'Keeping `paginatedRowModel: createPaginatedRowModel()` registered in `_rowModels` for a server-paginated + - 'Keeping `paginatedRowModel: createPaginatedRowModel()` registered in `rowModels` for a server-paginated table. The factory ships in your bundle for nothing AND it competes with `manualPagination`.' - Mixing `state.pagination` + `onPaginationChange` AND `atoms.pagination` for the same slice. `atoms` wins; the `state` plumbing is silently dead. Pick one. @@ -6149,8 +6149,8 @@ skills: function App() { const tableContainerRef = useRef(null) const table = useTable({ - _features: { rowSortingFeature, columnSizingFeature }, - _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features: { rowSortingFeature, columnSizingFeature }, + rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, data, }) return ( @@ -6302,8 +6302,8 @@ skills: // 2. Critical: flatten row type for form path-keys (avoids TS2589) type FormRow = Omit - const _features = tableFeatures({ rowPaginationFeature, columnFilteringFeature }) - const columnHelper = createColumnHelper() + const features = tableFeatures({ rowPaginationFeature, columnFilteringFeature }) + const columnHelper = createColumnHelper() function App() { const form = useAppForm({ @@ -6332,8 +6332,8 @@ skills: void dataLength const table = useTable({ - _features, - _rowModels: { + features, + rowModels: { filteredRowModel: createFilteredRowModel(filterFns), paginatedRowModel: createPaginatedRowModel(), }, @@ -6689,17 +6689,17 @@ tensions: 'Agents either over-wrap every component in Subscribe (verbose, slow to author) or under-wrap and ship tables that look fine in dev but break under React Compiler in prod. Symptoms: stale checkboxes, frozen sort indicators, broken pin buttons.' - - name: tree-shaking via _features vs ergonomic useLegacyTable + - name: tree-shaking via features vs ergonomic useLegacyTable skills: - setup - production-readiness - migrate-v8-to-v9 description: '`useLegacyTable` (from `@tanstack/react-table/legacy`) lets v8 code keep working without - declaring `_features`/`_rowModels`, but bundles every feature regardless of use.' + declaring `features`/`rowModels`, but bundles every feature regardless of use.' implication: Agents reach for `useLegacyTable` on v8→v9 migrations and never circle back to declare - `_features`, sacrificing the bundle wins that motivated the v9 redesign. + `features`, sacrificing the bundle wins that motivated the v9 redesign. cross_references: - from: setup to: state-management @@ -6762,7 +6762,7 @@ cross_references: reason: Subscribe boundaries are a top perf optimization on React - from: production-readiness to: setup - reason: '`_features` tree-shaking is decided at setup' + reason: '`features` tree-shaking is decided at setup' - from: compose-with-tanstack-virtual to: row-expanding reason: virtualized + expanding requires careful measurer + getSubRows interaction @@ -6827,7 +6827,7 @@ gaps: - skill: setup question: For vanilla JS (`@tanstack/table-core` direct), is `storeReactivityBindings()` strictly required, - or is there a no-reactivity path? `constructTable` reads `tableOptions._features.coreReativityFeature` + or is there a no-reactivity path? `constructTable` reads `tableOptions.features.coreReativityFeature` unconditionally — implies required, but want to confirm. context: Affects the vanilla failure mode set. Currently I have not added a failure mode for "uses constructTable @@ -6868,9 +6868,9 @@ gaps: models. Either documentation is aspirational or implementation is stubbed.' - issue: v9 createColumnHelper signature change detail: - v9 requires `createColumnHelper()` — TFeatures FIRST. v8 was `createColumnHelper()`. + v9 requires `createColumnHelper()` — TFeatures FIRST. v8 was `createColumnHelper()`. Every cluster-B example confirms this pattern (filters, filters-faceted, filters-fuzzy, sorting, pagination, - grouping, expanding, sub-components all use ``). + grouping, expanding, sub-components all use ``). - issue: 'Framework variation: Vue/Svelte/Solid/Angular use signal/reactive data getter' detail: | React: `useTable({ data, columns, ... })` — data is a value. @@ -6878,7 +6878,7 @@ gaps: Solid: `createTable({ get data() { return data() }, columns, ... })` — getter against signal. Svelte: `createTable({ get data() { return data }, ... })` — getter against $state rune. Angular: `injectTable(() => ({ data: this.data(), columns, ... }))` — whole config is a factory. - All use the same `tableFeatures({ ... })` and `_rowModels` shapes. The reactive plumbing differs. + All use the same `tableFeatures({ ... })` and `rowModels` shapes. The reactive plumbing differs. - issue: Faceting requires THREE row models in lockstep detail: createFacetedRowModel() is the base; createFacetedUniqueValues() and createFacetedMinMaxValues() @@ -6931,7 +6931,7 @@ gaps: No issue yet asks this verbatim because v9 is alpha and adoption is small, but every adoption issue shows the same disorientation. The skill needs a 1:1 mapping table from v8 imports to v9 feature/row-model imports, plus a "minimum boilerplate" - example showing _features and the tableFeatures registry. + example showing features and the tableFeatures registry. status: open - skill: migrate-v8-to-v9 question: How do I convert a v8 useReactTable site to v9 useTable + Subscribe? @@ -6944,7 +6944,7 @@ gaps: question: When should I use createTableHook vs useTable directly? context: | v9 adds `createTableHook` (React/Solid) for ergonomic composition: ``, - pre-configured `_features`, etc. Issues #6199 and #6244 reference it but no skill + pre-configured `features`, etc. Issues #6199 and #6244 reference it but no skill content covers the trade-offs vs the bare `useTable` API. Agents won't know when `createTableHook` is appropriate. status: open @@ -7092,7 +7092,7 @@ maintainer_interview: Stable `data` and `columns` references — most-asked confusion despite docs coverage in FAQ + data guide. 4d-IK3-b: - 'v9-SPECIFIC HIGH-FREQUENCY confusion: missing APIs / state slices when `_features` does + 'v9-SPECIFIC HIGH-FREQUENCY confusion: missing APIs / state slices when `features` does not include the relevant feature. v9 is the first version where this matters for TypeScript inference and runtime API exposure.' 4d-IK4: diff --git a/_artifacts/scratch/cluster-a-foundational.yaml b/_artifacts/scratch/cluster-a-foundational.yaml index 71773d99fd..b1db49ced6 100644 --- a/_artifacts/scratch/cluster-a-foundational.yaml +++ b/_artifacts/scratch/cluster-a-foundational.yaml @@ -7,13 +7,13 @@ skills: - name: 'Setup' slug: 'setup' domain: 'core-foundations' - description: 'Install a table adapter and wire up a first working table with `_features`, `_rowModels`, columns, and data.' + description: 'Install a table adapter and wire up a first working table with `features`, `rowModels`, columns, and data.' type: 'core' packages: ['@tanstack/table-core'] covers: - 'tableFeatures' - - '_features' - - '_rowModels' + - 'features' + - 'rowModels' - 'useTable' - 'constructTable' - '_createTable' @@ -30,8 +30,8 @@ skills: - 'Wire up the matching adapter (`useTable` / `injectTable` / `createTable` / `constructTable`) and render markup with `` or `flexRender`' - 'Use `@tanstack/table-core` + `storeReactivityBindings()` directly (vanilla JS) when no framework adapter exists' failure_modes: - - mistake: 'Omits `_features` and `_rowModels`' - mechanism: 'v9 requires `_features` (and an `_rowModels` map, even if empty) at the top of `useTable`/`constructTable` options. Without `_features`, TypeScript loses feature-state inference and runtime construction has no feature plugins to register.' + - mistake: 'Omits `features` and `rowModels`' + mechanism: 'v9 requires `features` (and an `rowModels` map, even if empty) at the top of `useTable`/`constructTable` options. Without `features`, TypeScript loses feature-state inference and runtime construction has no feature plugins to register.' wrong_pattern: | // v8-flavoured, breaks in v9 const table = useTable({ @@ -41,10 +41,10 @@ skills: }) correct_pattern: | // v9 minimal table - const _features = tableFeatures({}) // empty = core features only + const features = tableFeatures({}) // empty = core features only const table = useTable({ - _features, - _rowModels: {}, // core row model auto-included + features, + rowModels: {}, // core row model auto-included columns, data, }) @@ -54,24 +54,24 @@ skills: version_context: 'v9 alpha; affects every user upgrading from v8 — the hook is renamed (`useReactTable` → `useTable`) AND new required options were introduced' - mistake: 'Calls `tableFeatures({})` inside the component body' - mechanism: "A fresh `_features` object on each render destroys the table's stable reference for feature registration, the same way unstable `columns`/`data` cause infinite re-renders. `_features` must be hoisted to module scope or memoized." + mechanism: "A fresh `features` object on each render destroys the table's stable reference for feature registration, the same way unstable `columns`/`data` cause infinite re-renders. `features` must be hoisted to module scope or memoized." wrong_pattern: | function MyTable() { // ❌ new object every render -> potential re-construct + state churn - const _features = tableFeatures({ rowSortingFeature }) - const table = useTable({ _features, _rowModels: {}, columns, data }) + const features = tableFeatures({ rowSortingFeature }) + const table = useTable({ features, rowModels: {}, columns, data }) } correct_pattern: | // ✅ module-scoped, stable reference - const _features = tableFeatures({ rowSortingFeature }) + const features = tableFeatures({ rowSortingFeature }) function MyTable() { - const table = useTable({ _features, _rowModels: {}, columns, data }) + const table = useTable({ features, rowModels: {}, columns, data }) } source: 'docs/guide/data.md:184-244; examples/react/basic-use-table/src/main.tsx:56 (defined outside component)' priority: 'HIGH' status: 'active' - version_context: 'v9 alpha; new in v9 because v8 had no `_features` option' + version_context: 'v9 alpha; new in v9 because v8 had no `features` option' skills: ['state-management'] - mistake: 'Reaches for `stockFeatures` by default' @@ -80,8 +80,8 @@ skills: // ❌ ships every feature, even unused ones import { useTable, stockFeatures } from '@tanstack/react-table' const table = useTable({ - _features: stockFeatures, - _rowModels: {}, + features: stockFeatures, + rowModels: {}, columns, data, }) @@ -94,7 +94,7 @@ skills: rowPaginationFeature, } from '@tanstack/react-table' - const _features = tableFeatures({ + const features = tableFeatures({ rowSortingFeature, rowPaginationFeature, }) @@ -104,13 +104,13 @@ skills: version_context: 'v9 alpha; `stockFeatures` is documented but discouraged for new code' - mistake: 'Adds a row model without registering its feature' - mechanism: 'Row model factories like `createSortedRowModel` only run if the matching feature (e.g. `rowSortingFeature`) is also registered in `_features`. TypeScript flags this when state slices/APIs are accessed, but runtime silently degrades — `table.atoms.sorting` is undefined and sort handlers do nothing.' + mechanism: 'Row model factories like `createSortedRowModel` only run if the matching feature (e.g. `rowSortingFeature`) is also registered in `features`. TypeScript flags this when state slices/APIs are accessed, but runtime silently degrades — `table.atoms.sorting` is undefined and sort handlers do nothing.' wrong_pattern: | - // ❌ rowSortingFeature missing from _features — sortedRowModel orphaned - const _features = tableFeatures({ rowPaginationFeature }) + // ❌ rowSortingFeature missing from features — sortedRowModel orphaned + const features = tableFeatures({ rowPaginationFeature }) const table = useTable({ - _features, - _rowModels: { + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns), // no-op paginatedRowModel: createPaginatedRowModel(), }, @@ -119,13 +119,13 @@ skills: }) correct_pattern: | // ✅ feature + row model registered together - const _features = tableFeatures({ + const features = tableFeatures({ rowSortingFeature, rowPaginationFeature, }) const table = useTable({ - _features, - _rowModels: { + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns), paginatedRowModel: createPaginatedRowModel(), }, @@ -135,12 +135,12 @@ skills: source: 'docs/guide/row-models.md:46-78; examples/react/basic-external-atoms/src/main.tsx:27-30,81-92' priority: 'HIGH' status: 'active' - version_context: 'v9 alpha; new failure surface since v8 had no _features/feature-row-model pairing' + version_context: 'v9 alpha; new failure surface since v8 had no features/feature-row-model pairing' - name: 'Column Definitions' slug: 'column-definitions' domain: 'core-foundations' - description: 'Define columns with `createColumnHelper()` to extract data and render headers/cells/footers.' + description: 'Define columns with `createColumnHelper()` to extract data and render headers/cells/footers.' type: 'core' packages: ['@tanstack/table-core'] covers: @@ -176,9 +176,9 @@ skills: // ❌ v8 signature — TData ends up in the TFeatures slot const columnHelper = createColumnHelper() correct_pattern: | - // ✅ v9 — TFeatures first, TData second; use typeof _features - const _features = tableFeatures({ rowSortingFeature }) - const columnHelper = createColumnHelper() + // ✅ v9 — TFeatures first, TData second; use typeof features + const features = tableFeatures({ rowSortingFeature }) + const columnHelper = createColumnHelper() source: 'packages/table-core/src/helpers/columnHelper.ts:99-103; docs/framework/react/guide/migrating.md:484-499; examples/react/basic-external-atoms/src/main.tsx:32' priority: 'CRITICAL' status: 'active' @@ -233,7 +233,7 @@ skills: columnHelper.accessor('firstName', { header: 'First' }), columnHelper.accessor('lastName', { header: 'Last' }), ] - const table = useTable({ _features, _rowModels: {}, columns, data }) + const table = useTable({ features, rowModels: {}, columns, data }) } correct_pattern: | // ✅ memoized columns or module-scoped via columnHelper.columns([...]) @@ -246,7 +246,7 @@ skills: ]), [], ) - const table = useTable({ _features, _rowModels: {}, columns, data }) + const table = useTable({ features, rowModels: {}, columns, data }) } source: 'docs/faq.md:5-128; examples/react/basic-subscribe/src/main.tsx:51-127' priority: 'CRITICAL' @@ -259,8 +259,8 @@ skills: wrong_pattern: | // ❌ no getRowId -> rowSelection survives data updates but maps to wrong rows const table = useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, enableRowSelection: true, @@ -268,8 +268,8 @@ skills: correct_pattern: | // ✅ stable id from the row's own identifier const table = useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, getRowId: (row) => row.id, @@ -334,7 +334,7 @@ skills: const [pagination, setPagination] = React.useState(...) const table = useTable({ - _features, _rowModels: {...}, columns, data, + features, rowModels: {...}, columns, data, state: { pagination }, // ignored onPaginationChange: setPagination, atoms: { pagination: paginationAtom }, // wins @@ -344,7 +344,7 @@ skills: const paginationAtom = useCreateAtom({ pageIndex: 0, pageSize: 10 }) const table = useTable({ - _features, _rowModels: {...}, columns, data, + features, rowModels: {...}, columns, data, atoms: { pagination: paginationAtom }, // no state.pagination, no onPaginationChange needed }) @@ -359,7 +359,7 @@ skills: // ❌ state without callback — sort toggles never reach setSorting const [sorting, setSorting] = React.useState([]) const table = useTable({ - _features, _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features, rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, data, state: { sorting }, // no onSortingChange }) @@ -367,7 +367,7 @@ skills: // ✅ state + on*Change must be paired const [sorting, setSorting] = React.useState([]) const table = useTable({ - _features, _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features, rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, data, state: { sorting }, onSortingChange: setSorting, @@ -383,7 +383,7 @@ skills: // ❌ updates to initialState are ignored after first render function MyTable({ defaultSort }: { defaultSort: SortingState }) { const table = useTable({ - _features, _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features, rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, data, initialState: { sorting: defaultSort }, // ❌ later changes to defaultSort never sync }) @@ -393,7 +393,7 @@ skills: function MyTable({ defaultSort }: { defaultSort: SortingState }) { const [sorting, setSorting] = React.useState(defaultSort) const table = useTable({ - _features, _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features, rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, data, state: { sorting }, onSortingChange: setSorting, @@ -409,7 +409,7 @@ skills: wrong_pattern: | // ❌ direct baseAtoms write while external atom owns the slice const paginationAtom = useCreateAtom({ pageIndex: 0, pageSize: 10 }) - const table = useTable({ _features, _rowModels: {...}, columns, data, atoms: { pagination: paginationAtom } }) + const table = useTable({ features, rowModels: {...}, columns, data, atoms: { pagination: paginationAtom } }) // later, somewhere table.baseAtoms.pagination.set((old) => ({ ...old, pageIndex: 0 })) @@ -430,7 +430,7 @@ skills: // ❌ data is already paginated server-side, but table still slices it const dataQuery = useQuery({ queryKey: ['data', pagination], queryFn: fetchPage }) const table = useTable({ - _features, _rowModels: { paginatedRowModel: createPaginatedRowModel() }, + features, rowModels: { paginatedRowModel: createPaginatedRowModel() }, columns, data: dataQuery.data?.rows ?? [], rowCount: dataQuery.data?.rowCount, @@ -440,7 +440,7 @@ skills: correct_pattern: | // ✅ tell the table the server handles pagination const table = useTable({ - _features, _rowModels: {}, // can drop paginatedRowModel if fully server-side + features, rowModels: {}, // can drop paginatedRowModel if fully server-side columns, data: dataQuery.data?.rows ?? [], rowCount: dataQuery.data?.rowCount, @@ -458,7 +458,7 @@ skills: // ❌ external atom keeps its current value; only baseAtoms reset const sortingAtom = useCreateAtom([]) const table = useTable({ - _features, _rowModels: {...}, columns, data, + features, rowModels: {...}, columns, data, atoms: { sorting: sortingAtom }, }) // ... @@ -514,10 +514,10 @@ skills: wrong_pattern: | // ❌ "fuzzy" string never registered const table = useTable({ - _features, columns: [ + features, columns: [ columnHelper.accessor('fullName', { filterFn: 'fuzzy' }), ], - _rowModels: { + rowModels: { filteredRowModel: createFilteredRowModel(filterFns), // ❌ no fuzzy in here }, data, @@ -526,20 +526,20 @@ skills: // ✅ register the custom fn AND module-augment for type safety declare module '@tanstack/react-table' { interface FilterFns { - fuzzy: FilterFn + fuzzy: FilterFn } } - const fuzzyFilter: FilterFn = (row, columnId, value, addMeta) => { + const fuzzyFilter: FilterFn = (row, columnId, value, addMeta) => { const itemRank = rankItem(row.getValue(columnId), value) addMeta?.({ itemRank }) return itemRank.passed } const table = useTable({ - _features, + features, columns: [columnHelper.accessor('fullName', { filterFn: 'fuzzy' })], - _rowModels: { + rowModels: { filteredRowModel: createFilteredRowModel({ ...filterFns, fuzzy: fuzzyFilter }), }, data, @@ -570,14 +570,14 @@ skills: mechanism: '`row.columnFiltersMeta` is keyed by the column id that produced the meta (or `"__global__"` for the global filter). A sortFn must look up the SAME column id the filterFn used. The fuzzy filter→sort pattern only works when both reference the same column.' wrong_pattern: | // ❌ filter on 'fullName', sort reads meta from 'firstName' - const fuzzySort: SortFn = (a, b, columnId) => { + const fuzzySort: SortFn = (a, b, columnId) => { const meta = a.columnFiltersMeta['firstName'] // ❌ wrong key return meta ? compareItems(meta.itemRank, b.columnFiltersMeta['firstName'].itemRank) : 0 } columnHelper.accessor('fullName', { filterFn: 'fuzzy', sortFn: fuzzySort }) correct_pattern: | // ✅ sortFn uses the same columnId arg that the row's filterFn ran on - const fuzzySort: SortFn = (rowA, rowB, columnId) => { + const fuzzySort: SortFn = (rowA, rowB, columnId) => { let dir = 0 if (rowA.columnFiltersMeta[columnId]) { dir = compareItems( @@ -657,7 +657,7 @@ gaps: status: 'open' - skill: 'setup' - question: 'For vanilla JS (`@tanstack/table-core` direct), is `storeReactivityBindings()` strictly required, or is there a no-reactivity path? `constructTable` reads `tableOptions._features.coreReativityFeature` unconditionally — implies required, but want to confirm.' + question: 'For vanilla JS (`@tanstack/table-core` direct), is `storeReactivityBindings()` strictly required, or is there a no-reactivity path? `constructTable` reads `tableOptions.features.coreReativityFeature` unconditionally — implies required, but want to confirm.' context: 'Affects the vanilla failure mode set. Currently I have not added a failure mode for "uses constructTable without storeReactivityBindings" — would do so if confirmed required.' status: 'open' diff --git a/_artifacts/scratch/cluster-b-row-model-features.yaml b/_artifacts/scratch/cluster-b-row-model-features.yaml index a12bdd1668..20e41cb734 100644 --- a/_artifacts/scratch/cluster-b-row-model-features.yaml +++ b/_artifacts/scratch/cluster-b-row-model-features.yaml @@ -82,17 +82,17 @@ skills: - 'Wire up text/range/select per-column filters with debounced inputs (see examples/react/filters/src/main.tsx).' - 'Add a faceted filter UI: autocomplete from `column.getFacetedUniqueValues()` and a range slider from `column.getFacetedMinMaxValues()` (requires `createFacetedRowModel()` PLUS the unique/minMax row models).' - 'Implement fuzzy global search with `@tanstack/match-sorter-utils` and a custom `fuzzySort` that reads `row.columnFiltersMeta[columnId].itemRank`.' - - 'Switch a table to manual server-side filtering: set `manualFiltering: true`, omit the `filteredRowModel` from `_rowModels`, and pass pre-filtered `data` from the server.' + - 'Switch a table to manual server-side filtering: set `manualFiltering: true`, omit the `filteredRowModel` from `rowModels`, and pass pre-filtered `data` from the server.' - 'Make a tree table filter sub-rows by enabling `filterFromLeafRows: true` so a parent stays visible whenever any child matches.' failure_modes: - mistake: 'Forgetting `createFacetedRowModel()` while still registering `createFacetedUniqueValues()` / `createFacetedMinMaxValues()`.' mechanism: | - `createFacetedUniqueValues` and `createFacetedMinMaxValues` both compute their results from `column.getFacetedRowModel().flatRows`. Without the base `facetedRowModel` factory in `_rowModels.facetedRowModel`, `column_getFacetedRowModel` falls back to `table.getPreFilteredRowModel()` (see column-faceting/columnFacetingFeature.utils.ts lines 44-56), so facet values are still computed but **don't exclude the column's own active filter** — meaning a select dropdown showing options for a column will collapse to only the currently selected value once the user picks one. + `createFacetedUniqueValues` and `createFacetedMinMaxValues` both compute their results from `column.getFacetedRowModel().flatRows`. Without the base `facetedRowModel` factory in `rowModels.facetedRowModel`, `column_getFacetedRowModel` falls back to `table.getPreFilteredRowModel()` (see column-faceting/columnFacetingFeature.utils.ts lines 44-56), so facet values are still computed but **don't exclude the column's own active filter** — meaning a select dropdown showing options for a column will collapse to only the currently selected value once the user picks one. wrong_pattern: | ```tsx const table = useTable({ - _features: tableFeatures({ columnFacetingFeature, columnFilteringFeature }), - _rowModels: { + features: tableFeatures({ columnFacetingFeature, columnFilteringFeature }), + rowModels: { filteredRowModel: createFilteredRowModel(filterFns), // BUG: missing facetedRowModel - the unique/minMax helpers will use // the pre-filtered model so they include every filter EXCEPT none @@ -106,12 +106,12 @@ skills: ```tsx // From examples/react/filters-faceted/src/main.tsx const table = useTable({ - _features: tableFeatures({ + features: tableFeatures({ columnFacetingFeature, columnFilteringFeature, rowPaginationFeature, }), - _rowModels: { + rowModels: { filteredRowModel: createFilteredRowModel(filterFns), paginatedRowModel: createPaginatedRowModel(), facetedRowModel: createFacetedRowModel(), // REQUIRED base @@ -135,8 +135,8 @@ skills: // BUG: manualFiltering: true means the filteredRowModel is BYPASSED. // Filter state changes do nothing visible unless `data` is refetched. const table = useTable({ - _features: tableFeatures({ columnFilteringFeature }), - _rowModels: { + features: tableFeatures({ columnFilteringFeature }), + rowModels: { filteredRowModel: createFilteredRowModel(filterFns), }, data, @@ -153,8 +153,8 @@ skills: fetch('/api/rows?' + serialize(columnFilters)).then(r => r.json()) ) const table = useTable({ - _features: tableFeatures({ columnFilteringFeature }), - _rowModels: {}, // no filteredRowModel needed for manual filtering + features: tableFeatures({ columnFilteringFeature }), + rowModels: {}, // no filteredRowModel needed for manual filtering data, columns, manualFiltering: true, @@ -186,19 +186,19 @@ skills: import { rankItem, compareItems } from '@tanstack/match-sorter-utils' declare module '@tanstack/react-table' { - interface FilterFns { fuzzy: FilterFn } + interface FilterFns { fuzzy: FilterFn } interface FilterMeta { itemRank?: RankingInfo } } - const fuzzyFilter: FilterFn = (row, columnId, value, addMeta) => { + const fuzzyFilter: FilterFn = (row, columnId, value, addMeta) => { const itemRank = rankItem(row.getValue(columnId), value) addMeta?.({ itemRank }) return itemRank.passed } const table = useTable({ - _features, - _rowModels: { + features, + rowModels: { filteredRowModel: createFilteredRowModel({ ...filterFns, // KEEP built-ins fuzzy: fuzzyFilter, // ADD custom @@ -223,7 +223,7 @@ skills: const [columnFilters, setColumnFilters] = useState([]) // ^^ empty const table = useTable({ - _features, _rowModels: { filteredRowModel: createFilteredRowModel(filterFns) }, + features, rowModels: { filteredRowModel: createFilteredRowModel(filterFns) }, columns, data, initialState: { columnFilters: [{ id: 'name', value: 'John' }], // IGNORED @@ -240,7 +240,7 @@ skills: { id: 'name', value: 'John' }, // seeded here ]) const table = useTable({ - _features, _rowModels: { filteredRowModel: createFilteredRowModel(filterFns) }, + features, rowModels: { filteredRowModel: createFilteredRowModel(filterFns) }, columns, data, state: { columnFilters }, onColumnFiltersChange: setColumnFilters, @@ -268,8 +268,8 @@ skills: ```tsx // Override getColumnCanGlobalFilter or set per-column. const table = useTable({ - _features: tableFeatures({ globalFilteringFeature }), - _rowModels: { filteredRowModel: createFilteredRowModel(filterFns) }, + features: tableFeatures({ globalFilteringFeature }), + rowModels: { filteredRowModel: createFilteredRowModel(filterFns) }, columns, data, globalFilterFn: 'includesString', getColumnCanGlobalFilter: (column) => true, // include every column @@ -294,8 +294,8 @@ skills: // BUG: filterFromLeafRows hides ALL children that don't match, // even though the parent does match. const table = useTable({ - _features: tableFeatures({ columnFilteringFeature, rowExpandingFeature }), - _rowModels: { filteredRowModel: createFilteredRowModel(filterFns), expandedRowModel: createExpandedRowModel() }, + features: tableFeatures({ columnFilteringFeature, rowExpandingFeature }), + rowModels: { filteredRowModel: createFilteredRowModel(filterFns), expandedRowModel: createExpandedRowModel() }, columns, data, getSubRows: r => r.subRows, filterFromLeafRows: true, @@ -307,8 +307,8 @@ skills: ```tsx // Keep parent's whole sub-tree when parent matches: filter root-only. const table = useTable({ - _features: tableFeatures({ columnFilteringFeature, rowExpandingFeature }), - _rowModels: { + features: tableFeatures({ columnFilteringFeature, rowExpandingFeature }), + rowModels: { filteredRowModel: createFilteredRowModel(filterFns), expandedRowModel: createExpandedRowModel(), }, @@ -416,8 +416,8 @@ skills: }) const table = useTable({ - _features: tableFeatures({ rowSortingFeature }), - _rowModels: { + features: tableFeatures({ rowSortingFeature }), + rowModels: { sortedRowModel: createSortedRowModel({ // pass registry here ...sortFns, myCustom: (a, b, id) => a.original[id] - b.original[id], @@ -500,7 +500,7 @@ skills: import { compareItems } from '@tanstack/match-sorter-utils' import { sortFns } from '@tanstack/react-table' - const fuzzySort: SortFn = (rowA, rowB, columnId) => { + const fuzzySort: SortFn = (rowA, rowB, columnId) => { let dir = 0 if (rowA.columnFiltersMeta[columnId]) { dir = compareItems( @@ -577,8 +577,8 @@ skills: ```tsx // BUG: getPageCount returns 1, next/prev buttons are disabled const table = useTable({ - _features: tableFeatures({ rowPaginationFeature }), - _rowModels: {}, + features: tableFeatures({ rowPaginationFeature }), + rowModels: {}, data, // only 10 rows for the current page columns, manualPagination: true, @@ -594,8 +594,8 @@ skills: fetchPage(pagination.pageIndex, pagination.pageSize), ) const table = useTable({ - _features: tableFeatures({ rowPaginationFeature }), - _rowModels: {}, + features: tableFeatures({ rowPaginationFeature }), + rowModels: {}, data: dataQuery.rows, columns, manualPagination: true, @@ -631,8 +631,8 @@ skills: // Seed in useState OR use initialState only — never both. const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: 25 }) const table = useTable({ - _features: tableFeatures({ rowPaginationFeature }), - _rowModels: { paginatedRowModel: createPaginatedRowModel() }, + features: tableFeatures({ rowPaginationFeature }), + rowModels: { paginatedRowModel: createPaginatedRowModel() }, columns, data, state: { pagination }, onPaginationChange: setPagination, @@ -650,7 +650,7 @@ skills: wrong_pattern: | ```tsx const table = useTable({ - _features, _rowModels: { paginatedRowModel: createPaginatedRowModel(), filteredRowModel: createFilteredRowModel(filterFns) }, + features, rowModels: { paginatedRowModel: createPaginatedRowModel(), filteredRowModel: createFilteredRowModel(filterFns) }, columns, data, autoResetPageIndex: false, // user on page 5, then filters down to 2 pages // -> page 5 is empty. No automatic clamp. @@ -744,10 +744,10 @@ skills: wrong_pattern: | ```tsx // BUG: grouped rows show aggregates but can't be expanded. - const _features = tableFeatures({ columnGroupingFeature }) + const features = tableFeatures({ columnGroupingFeature }) const table = useTable({ - _features, - _rowModels: { groupedRowModel: createGroupedRowModel(aggregationFns) }, + features, + rowModels: { groupedRowModel: createGroupedRowModel(aggregationFns) }, columns, data, }) // row.getToggleExpandedHandler() -> TS error or undefined @@ -763,7 +763,7 @@ skills: rowExpandingFeature, } from '@tanstack/react-table' - const _features = tableFeatures({ + const features = tableFeatures({ columnGroupingFeature, rowExpandingFeature, rowPaginationFeature, @@ -772,8 +772,8 @@ skills: }) const table = useTable({ - _features, - _rowModels: { + features, + rowModels: { groupedRowModel: createGroupedRowModel(aggregationFns), expandedRowModel: createExpandedRowModel(), // + sorted, filtered, paginated as needed @@ -801,8 +801,8 @@ skills: ```tsx // BUG: v8-style option that doesn't exist in v9 const table = useTable({ - _features: tableFeatures({ columnGroupingFeature }), - _rowModels: { groupedRowModel: createGroupedRowModel(aggregationFns) }, + features: tableFeatures({ columnGroupingFeature }), + rowModels: { groupedRowModel: createGroupedRowModel(aggregationFns) }, columns, data, // @ts-ignore - this property doesn't exist on TableOptions in v9 aggregationFns: { @@ -816,8 +816,8 @@ skills: import { aggregationFns, createGroupedRowModel } from '@tanstack/react-table' const table = useTable({ - _features: tableFeatures({ columnGroupingFeature, rowExpandingFeature }), - _rowModels: { + features: tableFeatures({ columnGroupingFeature, rowExpandingFeature }), + rowModels: { groupedRowModel: createGroupedRowModel({ ...aggregationFns, myCustomAggregation: (columnId, leafRows, childRows) => { @@ -882,8 +882,8 @@ skills: ```tsx // BUG: column order is overridden by reorder mode const table = useTable({ - _features, - _rowModels: { groupedRowModel: createGroupedRowModel(aggregationFns) }, + features, + rowModels: { groupedRowModel: createGroupedRowModel(aggregationFns) }, columns, data, initialState: { columnOrder: ['firstName', 'lastName', 'age', 'status'], // explicit @@ -895,8 +895,8 @@ skills: correct_pattern: | ```tsx const table = useTable({ - _features, - _rowModels: { groupedRowModel: createGroupedRowModel(aggregationFns) }, + features, + rowModels: { groupedRowModel: createGroupedRowModel(aggregationFns) }, columns, data, initialState: { columnOrder: ['firstName', 'lastName', 'age', 'status'], @@ -1015,8 +1015,8 @@ skills: // For pure tree data, omit getRowCanExpand and let it auto-detect: // From examples/react/expanding/src/main.tsx const table = useTable({ - _features, - _rowModels: { expandedRowModel: createExpandedRowModel(), /* ... */ }, + features, + rowModels: { expandedRowModel: createExpandedRowModel(), /* ... */ }, columns, data, getSubRows: row => row.subRows, // no getRowCanExpand — row.getCanExpand() is true only when subRows.length > 0 @@ -1025,8 +1025,8 @@ skills: // For pure detail panels, override and skip getSubRows: // From examples/react/sub-components/src/main.tsx const table = useTable({ - _features: tableFeatures({ rowExpandingFeature }), - _rowModels: { expandedRowModel: createExpandedRowModel() }, + features: tableFeatures({ rowExpandingFeature }), + rowModels: { expandedRowModel: createExpandedRowModel() }, columns, data, getRowCanExpand: (row) => true, // every row expands to show }) @@ -1054,8 +1054,8 @@ skills: // From docs/guide/expanding.md // Default behavior (children flow through pagination): const table = useTable({ - _features, - _rowModels: { expandedRowModel: createExpandedRowModel(), paginatedRowModel: createPaginatedRowModel() }, + features, + rowModels: { expandedRowModel: createExpandedRowModel(), paginatedRowModel: createPaginatedRowModel() }, columns, data, getSubRows: r => r.subRows, // paginateExpandedRows defaults to true @@ -1111,8 +1111,8 @@ skills: // BUG: manualExpanding bypasses the expanded row model; // sub-rows are never flattened into view. const table = useTable({ - _features: tableFeatures({ rowExpandingFeature }), - _rowModels: { expandedRowModel: createExpandedRowModel() }, // ignored + features: tableFeatures({ rowExpandingFeature }), + rowModels: { expandedRowModel: createExpandedRowModel() }, // ignored columns, data, getSubRows: r => r.subRows, manualExpanding: true, @@ -1124,8 +1124,8 @@ skills: // returns a pre-flattened view based on which rows are expanded. // From docs/guide/expanding.md const table = useTable({ - _features: tableFeatures({ rowExpandingFeature }), - _rowModels: {}, // no expandedRowModel for manual mode + features: tableFeatures({ rowExpandingFeature }), + rowModels: {}, // no expandedRowModel for manual mode columns, data: dataQuery.data, // server returns flattened rows when expanded manualExpanding: true, @@ -1135,8 +1135,8 @@ skills: // For client-side tree, omit manualExpanding: const table = useTable({ - _features: tableFeatures({ rowExpandingFeature }), - _rowModels: { expandedRowModel: createExpandedRowModel() }, + features: tableFeatures({ rowExpandingFeature }), + rowModels: { expandedRowModel: createExpandedRowModel() }, columns, data, getSubRows: r => r.subRows, }) @@ -1167,7 +1167,7 @@ gaps: detail: '`table_getSelectedRowModel`, `table_getFilteredSelectedRowModel`, and `table_getGroupedSelectedRowModel` all call `selectRowsFn(table.getCoreRowModel())` (rowSelectionFeature.utils.ts:173-244). The function bodies are the same except for comments. Per docs row-models.md they should dispatch on filtered/grouped models. Either documentation is aspirational or implementation is stubbed.' - issue: 'v9 createColumnHelper signature change' - detail: 'v9 requires `createColumnHelper()` — TFeatures FIRST. v8 was `createColumnHelper()`. Every cluster-B example confirms this pattern (filters, filters-faceted, filters-fuzzy, sorting, pagination, grouping, expanding, sub-components all use ``).' + detail: 'v9 requires `createColumnHelper()` — TFeatures FIRST. v8 was `createColumnHelper()`. Every cluster-B example confirms this pattern (filters, filters-faceted, filters-fuzzy, sorting, pagination, grouping, expanding, sub-components all use ``).' - issue: 'Framework variation: Vue/Svelte/Solid/Angular use signal/reactive data getter' detail: | @@ -1176,7 +1176,7 @@ gaps: Solid: `createTable({ get data() { return data() }, columns, ... })` — getter against signal. Svelte: `createTable({ get data() { return data }, ... })` — getter against $state rune. Angular: `injectTable(() => ({ data: this.data(), columns, ... }))` — whole config is a factory. - All use the same `tableFeatures({ ... })` and `_rowModels` shapes. The reactive plumbing differs. + All use the same `tableFeatures({ ... })` and `rowModels` shapes. The reactive plumbing differs. - issue: 'Faceting requires THREE row models in lockstep' detail: "createFacetedRowModel() is the base; createFacetedUniqueValues() and createFacetedMinMaxValues() both depend on it (column_getFacetedUniqueValues / column_getFacetedMinMaxValues both call column_getFacetedRowModel internally for the memoDep). Phase 1+2 note flagged this as 'agents commonly forget the base faceted row model'. Confirmed by reading source." diff --git a/_artifacts/scratch/cluster-c-ui-state-features.yaml b/_artifacts/scratch/cluster-c-ui-state-features.yaml index c5da3f5611..44b91e11b8 100644 --- a/_artifacts/scratch/cluster-c-ui-state-features.yaml +++ b/_artifacts/scratch/cluster-c-ui-state-features.yaml @@ -235,7 +235,7 @@ skills: wrong_pattern: | // ❌ Live resize + getSize() on every cell + un-memoized body const table = useTable({ - _features: tableFeatures({ columnSizingFeature, columnResizingFeature }), + features: tableFeatures({ columnSizingFeature, columnResizingFeature }), columnResizeMode: 'onChange', //... }) @@ -343,14 +343,14 @@ skills: wrong_pattern: | // ❌ v8 syntax — no longer disables pinning in v9 const table = useTable({ - _features: tableFeatures({ columnPinningFeature }), + features: tableFeatures({ columnPinningFeature }), enablePinning: false, // ignored at table level in v9 //... }) correct_pattern: | // ✅ v9: split into two table-level options const table = useTable({ - _features: tableFeatures({ columnPinningFeature, rowPinningFeature }), + features: tableFeatures({ columnPinningFeature, rowPinningFeature }), enableColumnPinning: false, // turns off column pinning enableRowPinning: false, // turns off row pinning (or row => row.original.locked) //... @@ -522,7 +522,7 @@ skills: columnHelper.accessor('lastName', { ... }), ] const table = useTable({ - _features: tableFeatures({ columnPinningFeature, columnResizingFeature }), + features: tableFeatures({ columnPinningFeature, columnResizingFeature }), columns, data, }) @@ -638,14 +638,14 @@ skills: wrong_pattern: | // ❌ row.id defaults to row.index; pin survives wrong rows after refetch const table = useTable({ - _features: tableFeatures({ rowPinningFeature, rowPaginationFeature }), + features: tableFeatures({ rowPinningFeature, rowPaginationFeature }), data, // refetched periodically //... }) correct_pattern: | // ✅ Stable row identity const table = useTable({ - _features: tableFeatures({ rowPinningFeature, rowPaginationFeature }), + features: tableFeatures({ rowPinningFeature, rowPaginationFeature }), data, getRowId: row => row.userId, // or row.uuid, row.id from API, etc. //... @@ -683,14 +683,14 @@ skills: wrong_pattern: | // ❌ Expecting pinned rows to vanish on filter, but they don't (default) const table = useTable({ - _features: tableFeatures({ rowPinningFeature, columnFilteringFeature }), + features: tableFeatures({ rowPinningFeature, columnFilteringFeature }), //... // keepPinnedRows defaults to true; pinned rows survive filtering }) correct_pattern: | // ✅ Be explicit about which UX you want const table = useTable({ - _features: tableFeatures({ rowPinningFeature, columnFilteringFeature }), + features: tableFeatures({ rowPinningFeature, columnFilteringFeature }), keepPinnedRows: false, // pinned rows disappear when filtered/paginated out //... }) @@ -849,7 +849,7 @@ skills: wrong_pattern: | // ❌ Server-side pagination + default row.id = row.index const table = useTable({ - _features: tableFeatures({ rowSelectionFeature, rowPaginationFeature }), + features: tableFeatures({ rowSelectionFeature, rowPaginationFeature }), data, // only the current page from the server manualPagination: true, rowCount, // server-provided total @@ -860,7 +860,7 @@ skills: correct_pattern: | // ✅ Stable row id keyed to the primary key the server uses const table = useTable({ - _features: tableFeatures({ rowSelectionFeature, rowPaginationFeature }), + features: tableFeatures({ rowSelectionFeature, rowPaginationFeature }), data, manualPagination: true, rowCount, @@ -906,7 +906,7 @@ skills: wrong_pattern: | // ❌ Checkbox "select all" + single-select mode const table = useTable({ - _features: tableFeatures({ rowSelectionFeature }), + features: tableFeatures({ rowSelectionFeature }), enableMultiRowSelection: false, // radio-like //... }) @@ -920,7 +920,7 @@ skills: correct_pattern: | // ✅ Radio inputs, no toggle-all header const table = useTable({ - _features: tableFeatures({ rowSelectionFeature }), + features: tableFeatures({ rowSelectionFeature }), enableMultiRowSelection: false, getRowId: row => row.id, //... @@ -1030,14 +1030,14 @@ skills: // (which is correct for most cases but surprising if you wanted // parent-only selection for a "select this group as a whole" UX) const table = useTable({ - _features: tableFeatures({ rowSelectionFeature, rowExpandingFeature }), + features: tableFeatures({ rowSelectionFeature, rowExpandingFeature }), getSubRows: row => row.subRows, // enableSubRowSelection unset — defaults to true }) correct_pattern: | // ✅ Opt out of parent->child propagation explicitly const table = useTable({ - _features: tableFeatures({ rowSelectionFeature, rowExpandingFeature }), + features: tableFeatures({ rowSelectionFeature, rowExpandingFeature }), getSubRows: row => row.subRows, enableSubRowSelection: false, // toggling parent doesn't touch subRows }) diff --git a/_artifacts/scratch/cluster-d-framework-adapters.yaml b/_artifacts/scratch/cluster-d-framework-adapters.yaml index 8c0c9f1466..f35c24b515 100644 --- a/_artifacts/scratch/cluster-d-framework-adapters.yaml +++ b/_artifacts/scratch/cluster-d-framework-adapters.yaml @@ -56,8 +56,8 @@ skills: mechanism: 'When a slice is owned both ways, external atoms take precedence over external state. The on[State]Change callback may stop firing or write into a base atom whose value is shadowed by the external atom, producing surprising divergence.' wrong_pattern: | const table = useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, atoms: { pagination: paginationAtom }, @@ -67,8 +67,8 @@ skills: correct_pattern: | // Pick exactly one source of truth per slice. const table = useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, atoms: { pagination: paginationAtom }, @@ -141,8 +141,8 @@ skills: wrong_pattern: | const pagination = ref({ pageIndex: 0, pageSize: 10 }) const table = useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, state: { pagination }, @@ -153,8 +153,8 @@ skills: correct_pattern: | const pagination = ref({ pageIndex: 0, pageSize: 10 }) const table = useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, state: { @@ -231,16 +231,16 @@ skills: wrong_pattern: | const [data] = createSignal(makeData(100)) const table = createTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data: data(), }) correct_pattern: | const [data] = createSignal(makeData(100)) const table = createTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, get data() { return data() }, }) @@ -318,8 +318,8 @@ skills: wrong_pattern: | let pagination = $state({ pageIndex: 0, pageSize: 10 }) const table = createTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, state: { pagination }, @@ -330,8 +330,8 @@ skills: correct_pattern: | let pagination = $state({ pageIndex: 0, pageSize: 10 }) const table = createTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, get data() { return data }, state: { @@ -382,15 +382,15 @@ skills: mechanism: 'injectTable expects a () => options factory and reruns it when read signals change. Passing a plain object skips signal tracking and the table never resyncs when source signals update.' wrong_pattern: | readonly table = injectTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data: this.data(), }) correct_pattern: | readonly table = injectTable(() => ({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data: this.data(), })) @@ -451,22 +451,22 @@ skills: mechanism: 'TableController owns the underlying table instance and subscriptions. Constructing it in render creates fresh subscriptions and discards prior state every cycle, causing data loss and double-subscribed host updates.' wrong_pattern: | protected render() { - const tableController = new TableController(this) + const tableController = new TableController(this) const table = tableController.table({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data: this._data, }) return html`...` } correct_pattern: | - private tableController = new TableController(this) + private tableController = new TableController(this) protected render() { const table = this.tableController.table({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data: this._data, }) @@ -506,7 +506,7 @@ skills: } correct_pattern: | // wire external atoms through table.atoms or maintain a separate subscription - private tableController = new TableController(this) + private tableController = new TableController(this) private _externalAtom = createAtom({ count: 0 }) private _unsub?: () => void @@ -544,36 +544,36 @@ skills: - 'initialState' - 'createTableHook (createAppColumnHelper, useAppTable, useTableContext, useCellContext, useHeaderContext)' tasks: - - 'Set up useTable in Preact with stable references for data, columns, and _features.' + - 'Set up useTable in Preact with stable references for data, columns, and features.' - 'Optimize a large Preact table by passing () => null as the selector and subscribing lower in the tree.' - 'Build reusable component registries with createTableHook in Preact.' failure_modes: - - mistake: 'Recreating columns or _features on every render' - mechanism: 'Preact relies on stable references for table options. New columns or _features arrays each render force useTable to call setOptions and rebuild derived state, undoing the work selectors and Subscribe are meant to save.' + - mistake: 'Recreating columns or features on every render' + mechanism: 'Preact relies on stable references for table options. New columns or features arrays each render force useTable to call setOptions and rebuild derived state, undoing the work selectors and Subscribe are meant to save.' wrong_pattern: | function App({ data }) { const columns = [ { accessorKey: 'firstName', header: 'First name' }, ] - const _features = tableFeatures({}) + const features = tableFeatures({}) const table = useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, }) return null } correct_pattern: | - const _features = tableFeatures({}) + const features = tableFeatures({}) const columns = [ { accessorKey: 'firstName', header: 'First name' }, ] function App({ data }) { const table = useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, }) @@ -613,8 +613,8 @@ skills: mechanism: 'External atoms take precedence over external state. Mixing them silently hides on[State]Change-driven setState writes and leaves React-style state stale.' wrong_pattern: | const table = useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, atoms: { pagination: paginationAtom }, @@ -624,8 +624,8 @@ skills: correct_pattern: | // Pick exactly one source of truth per slice. const table = useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, atoms: { pagination: paginationAtom }, @@ -897,17 +897,17 @@ skills: mechanism: 'TableController.addController and store subscriptions run in the constructor. Recreating it per render leaks subscriptions, drops the prior table instance (losing state), and double-triggers host updates.' wrong_pattern: | protected render() { - const controller = new TableController(this) - const table = controller.table({ _features, _rowModels: {}, columns, data: this._data }) + const controller = new TableController(this) + const table = controller.table({ features, rowModels: {}, columns, data: this._data }) return html`...` } correct_pattern: | - private tableController = new TableController(this) + private tableController = new TableController(this) protected render() { const table = this.tableController.table({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data: this._data, }) diff --git a/_artifacts/scratch/cluster-e-lifecycle-composition.yaml b/_artifacts/scratch/cluster-e-lifecycle-composition.yaml index ec21bc0ed8..804280d6d1 100644 --- a/_artifacts/scratch/cluster-e-lifecycle-composition.yaml +++ b/_artifacts/scratch/cluster-e-lifecycle-composition.yaml @@ -19,7 +19,7 @@ skills: status: ready description: > End-to-end first-table journey: install the framework adapter, declare - `_features` via `tableFeatures()`, declare `_rowModels` factories with + `features` via `tableFeatures()`, declare `rowModels` factories with their *Fns parameters, create a column helper with both `TFeatures` and `TData` generics, instantiate `useTable` / `injectTable` / `createTable`, and render headers + cells with `table.FlexRender` (or `*flexRender*` @@ -30,9 +30,9 @@ skills: `@tanstack/solid-table`, `@tanstack/svelte-table` (Svelte 5+), `@tanstack/preact-table`, `@tanstack/lit-table`). - |- - Declaring the minimum-viable v9 table (no features) — must still pass `_features: tableFeatures({})` and `_rowModels: {}`. Core row model is automatic; you only register filtered/sorted/paginated/etc. when you use them. + Declaring the minimum-viable v9 table (no features) — must still pass `features: tableFeatures({})` and `rowModels: {}`. Core row model is automatic; you only register filtered/sorted/paginated/etc. when you use them. - |- - `createColumnHelper()` and the new `columnHelper.columns([...])` variadic wrapper for preserving each column's `TValue` in nested/group columns. + `createColumnHelper()` and the new `columnHelper.columns([...])` variadic wrapper for preserving each column's `TValue` in nested/group columns. - Rendering with `` / `` (preferred) or the standalone `` import. `flexRender(def, ctx)` still works. @@ -53,9 +53,9 @@ skills: - '@tanstack/lit-table' tasks: - 'Render a basic v9 table with 3 columns and an in-memory array.' - - 'Add sorting: register `rowSortingFeature` in `_features` and `sortedRowModel: createSortedRowModel(sortFns)` in `_rowModels`.' + - 'Add sorting: register `rowSortingFeature` in `features` and `sortedRowModel: createSortedRowModel(sortFns)` in `rowModels`.' - 'Add pagination + filtering on top of sorting without touching the rest of the setup.' - - 'Type a `ColumnDef[]` array outside the component for stable references.' + - 'Type a `ColumnDef[]` array outside the component for stable references.' correct_pattern: | // React — minimum viable v9 table import { @@ -70,8 +70,8 @@ skills: type Person = { firstName: string; lastName: string; age: number } // Define OUTSIDE the component for stable identity. - const _features = tableFeatures({ rowSortingFeature }) - const columnHelper = createColumnHelper() + const features = tableFeatures({ rowSortingFeature }) + const columnHelper = createColumnHelper() const columns = columnHelper.columns([ columnHelper.accessor('firstName', { header: 'First' }), @@ -81,8 +81,8 @@ skills: function PeopleTable({ data }: { data: Person[] }) { const table = useTable({ - _features, - _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, data, }) @@ -108,9 +108,9 @@ skills: // BAD: agents trained on v8 will produce this and it will not compile. // (1) `useReactTable` was removed in favor of `useTable`. // (2) `getCoreRowModel: getCoreRowModel()` is no longer accepted — - // core is implicit; everything else moved to `_rowModels`. + // core is implicit; everything else moved to `rowModels`. // (3) `createColumnHelper()` is missing the TFeatures generic. - // (4) No `_features` => "Property '_features' is missing in type". + // (4) No `features` => "Property 'features' is missing in type". import { useReactTable, getCoreRowModel, createColumnHelper, flexRender } from '@tanstack/react-table' @@ -121,12 +121,12 @@ skills: getCoreRowModel: getCoreRowModel(), // removed option }) failure_modes: - - "Forgetting `_features: tableFeatures({})` — the option is required even for a 'no features' table. Type error: '_features' is missing." - - 'Skipping `_rowModels: {}` — same as above. Core is automatic but the option key itself must be present.' - - "Calling `createColumnHelper()` instead of `createColumnHelper()`. The generic order changed in v9 and the old shape doesn't compile." - - 'Defining `_features` / `columns` / `data` literals inside the render body — every render produces a new reference and busts table-internal memoization. Always declare these outside the component or wrap in `useMemo`.' + - "Forgetting `features: tableFeatures({})` — the option is required even for a 'no features' table. Type error: 'features' is missing." + - 'Skipping `rowModels: {}` — same as above. Core is automatic but the option key itself must be present.' + - "Calling `createColumnHelper()` instead of `createColumnHelper()`. The generic order changed in v9 and the old shape doesn't compile." + - 'Defining `features` / `columns` / `data` literals inside the render body — every render produces a new reference and busts table-internal memoization. Always declare these outside the component or wrap in `useMemo`.' - 'Importing `useReactTable` (v8) or `createAngularTable` (v8 Angular) — both were renamed. v9 uses `useTable` / `injectTable` / `createTable` consistently across adapters.' - - "Reaching for `useLegacyTable` for a new project. It's deprecated and ships every feature in the bundle. New code must use `useTable` with explicit `_features`." + - "Reaching for `useLegacyTable` for a new project. It's deprecated and ships every feature in the bundle. New code must use `useTable` with explicit `features`." - slug: migrate-v8-to-v9 type: lifecycle @@ -143,9 +143,9 @@ skills: covers: - Hook rename per adapter (React, Angular, Solid, Vue, Preact, Svelte 5+, Lit, vanilla). - |- - `_features` + `_rowModels` becoming required options; row-model factories now take their *Fns set as a parameter. + `features` + `rowModels` becoming required options; row-model factories now take their *Fns set as a parameter. - |- - `createColumnHelper()` → `createColumnHelper()` (generic order + arity change). + `createColumnHelper()` → `createColumnHelper()` (generic order + arity change). - |- State surface: `table.getState()` → `table.store.state` (full) or `table.state` (selector output) or `table.atoms..get()`. - |- @@ -177,10 +177,10 @@ skills: - '@tanstack/lit-table' - '@tanstack/table-core' tasks: - - 'Upgrade a v8 React table to v9 by renaming `useReactTable` → `useTable`, moving `getCoreRowModel`/`getFilteredRowModel`/`getSortedRowModel`/`getPaginationRowModel` options into `_rowModels`, and adding `_features: tableFeatures({...})`.' + - 'Upgrade a v8 React table to v9 by renaming `useReactTable` → `useTable`, moving `getCoreRowModel`/`getFilteredRowModel`/`getSortedRowModel`/`getPaginationRowModel` options into `rowModels`, and adding `features: tableFeatures({...})`.' - 'Bridge a v8 React table to v9 via `useLegacyTable` from `@tanstack/react-table/legacy` so the rest of the app can upgrade incrementally.' - 'Rename `table.getState()` reads throughout the codebase to `table.store.state` (full read) or `table.state` (typed selector output) or `table.atoms..get()` (single-slice atom read).' - - 'Update all `createColumnHelper()` call sites to `createColumnHelper()` and adjust `ColumnDef` / `Column` / `Row` / `Cell` type annotations to the new `TFeatures`-first generic order.' + - 'Update all `createColumnHelper()` call sites to `createColumnHelper()` and adjust `ColumnDef` / `Column` / `Row` / `Cell` type annotations to the new `TFeatures`-first generic order.' correct_pattern: | // === v9 (correct) === import { @@ -200,7 +200,7 @@ skills: } from '@tanstack/react-table' import type { ColumnDef } from '@tanstack/react-table' - const _features = tableFeatures({ + const features = tableFeatures({ rowSortingFeature, rowPaginationFeature, columnFilteringFeature, @@ -208,9 +208,9 @@ skills: columnResizingFeature, // explicit — formerly part of ColumnSizing }) - const columnHelper = createColumnHelper() + const columnHelper = createColumnHelper() - const columns: ColumnDef[] = columnHelper.columns([ + const columns: ColumnDef[] = columnHelper.columns([ columnHelper.accessor('name', { header: 'Name', sortFn: 'alphanumeric', // renamed from sortingFn @@ -218,8 +218,8 @@ skills: ]) const table = useTable({ - _features, - _rowModels: { + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns), filteredRowModel: createFilteredRowModel(filterFns), paginatedRowModel: createPaginatedRowModel(), @@ -245,7 +245,7 @@ skills: import { useReactTable, // (1) renamed → useTable getCoreRowModel, // (2) no longer accepted as an option; - getFilteredRowModel, // move to `_rowModels` as factories + getFilteredRowModel, // move to `rowModels` as factories getSortedRowModel, // created via `createSortedRowModel(sortFns)` etc. getPaginationRowModel, createColumnHelper, // (3) needs now @@ -268,7 +268,7 @@ skills: const table = useReactTable({ columns, data, - getCoreRowModel: getCoreRowModel(), // (2) move into `_rowModels` + getCoreRowModel: getCoreRowModel(), // (2) move into `rowModels` getFilteredRowModel: getFilteredRowModel(), getSortedRowModel: getSortedRowModel(), getPaginationRowModel: getPaginationRowModel(), @@ -301,10 +301,10 @@ skills: }) failure_modes: - 'Importing `useReactTable` / `createAngularTable` / `createSolidTable` (v8 names). All adapters consolidated to `useTable` / `injectTable` / `createTable` in v9. The v8 imports will not exist and will fail at module-resolution time.' - - 'Passing `getCoreRowModel: getCoreRowModel()` / `getSortedRowModel: getSortedRowModel()` as root options. These were removed — sortedRowModel/filteredRowModel/etc. now live under `_rowModels` and are produced by `createSortedRowModel(sortFns)`-style factories. Core is automatic.' + - 'Passing `getCoreRowModel: getCoreRowModel()` / `getSortedRowModel: getSortedRowModel()` as root options. These were removed — sortedRowModel/filteredRowModel/etc. now live under `rowModels` and are produced by `createSortedRowModel(sortFns)`-style factories. Core is automatic.' - 'Calling `createSortedRowModel()` without passing `sortFns`. The factories now REQUIRE their *Fns parameter for tree-shaking — `createFilteredRowModel(filterFns)`, `createSortedRowModel(sortFns)`, `createGroupedRowModel(aggregationFns)`.' - - "Omitting `_features` entirely. The option is required even for a no-features table — pass `_features: tableFeatures({})` or `_features: stockFeatures` if you want v8-like 'everything on'." - - 'Calling `createColumnHelper()` (v8 arity). v9 requires `createColumnHelper()`. `typeof _features` is the standard idiom — declare features once at module scope and reuse the type.' + - "Omitting `features` entirely. The option is required even for a no-features table — pass `features: tableFeatures({})` or `features: stockFeatures` if you want v8-like 'everything on'." + - 'Calling `createColumnHelper()` (v8 arity). v9 requires `createColumnHelper()`. `typeof features` is the standard idiom — declare features once at module scope and reuse the type.' - 'Reading state via `table.getState()`. The method was removed. Use `table.store.state` for a flat snapshot, `table.state` if you passed a `useTable` selector, or `table.atoms..get()` for a single slice.' - 'Renaming misses: `sortingFn` (column def) → `sortFn`, `sortingFns` → `sortFns`, `getSortingFn()` → `getSortFn()`, `getAutoSortingFn()` → `getAutoSortFn()`, `SortingFn`/`SortingFns` types → `SortFn`/`SortFns`. TypeScript will surface these but the agent will try the v8 names first.' - 'Using `enablePinning: true`. It was split into `enableColumnPinning` and `enableRowPinning`. Pick one (or both).' @@ -323,7 +323,7 @@ skills: `manualPagination` / `manualGrouping` / `manualExpanding` for whatever the server now owns, supply `rowCount` (and/or `pageCount`) so the table can paginate without seeing all rows, and remove the corresponding - `_rowModels` entries (you don't need `paginatedRowModel` if pagination + `rowModels` entries (you don't need `paginatedRowModel` if pagination is server-side). State for the server-managed slices is best owned EITHER via external TanStack Store atoms (passed via `options.atoms`) OR via classic `state` + `on*Change` controlled state — both work. @@ -333,7 +333,7 @@ skills: - Setting `manualSorting`, `manualFiltering`, `manualPagination`, `manualGrouping`, `manualExpanding` so the table stops trying to slice rows it doesn't have. - - Removing the matching `_rowModels` keys so unused factories don't + - Removing the matching `rowModels` keys so unused factories don't ship (don't register `paginatedRowModel` if the server paginates). - Providing `rowCount` (and optionally `pageCount`) so `table.getPageCount()` / `getCanNextPage()` work without local rows. @@ -363,7 +363,7 @@ skills: import { useCreateAtom, useSelector } from '@tanstack/react-store' import type { PaginationState } from '@tanstack/react-table' - const _features = tableFeatures({ rowPaginationFeature }) + const features = tableFeatures({ rowPaginationFeature }) function ServerTable({ columns }) { // 1) Own pagination in an external atom. @@ -383,10 +383,10 @@ skills: }) // 3) Manual pagination + `rowCount` for getPageCount(). Note: no - // `paginatedRowModel` in `_rowModels` — server paginates. + // `paginatedRowModel` in `rowModels` — server paginates. const table = useTable({ - _features, - _rowModels: {}, // core only + features, + rowModels: {}, // core only columns, data: dataQuery.data?.rows ?? [], rowCount: dataQuery.data?.rowCount, @@ -401,8 +401,8 @@ skills: // This makes the table try to slice the (already-sliced) `data` array // a second time, producing rows that don't exist. const table = useTable({ - _features, - _rowModels: { paginatedRowModel: createPaginatedRowModel() }, + features, + rowModels: { paginatedRowModel: createPaginatedRowModel() }, columns, data: serverPage.rows, // missing: manualPagination + rowCount @@ -412,8 +412,8 @@ skills: // `Math.ceil(rows.length / pageSize)` which is the page size, not the // total — the pager shows "Page 1 of 1" forever. const table = useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data: serverPage.rows, manualPagination: true, @@ -430,14 +430,14 @@ skills: // `state + on*Change`. Don't pass `state` without `on*Change`. const [pagination, setPagination] = useState({...}) useTable({ - _features, _rowModels: {}, columns, data, + features, rowModels: {}, columns, data, state: { pagination }, // missing: onPaginationChange: setPagination manualPagination: true, }) failure_modes: - 'Forgetting `manualPagination: true` (or `manualSorting` / `manualFiltering`). The table will re-sort/re-filter/re-paginate the already-server-processed rows, producing visually incorrect or duplicated results.' - - 'Leaving `paginatedRowModel: createPaginatedRowModel()` registered when the server paginates. The factory ships in your bundle for no reason AND the table slices server-sliced data. Drop it from `_rowModels`.' + - 'Leaving `paginatedRowModel: createPaginatedRowModel()` registered when the server paginates. The factory ships in your bundle for no reason AND the table slices server-sliced data. Drop it from `rowModels`.' - "Omitting `rowCount`. Without it, `getPageCount()` is computed from `data.length / pageSize` — which equals 1 if the server returned a single page. Pager UIs lock at 'Page 1 of 1'." - 'Passing `state.pagination` without `onPaginationChange`. The library treats `state` as controlled; without a writeback handler, `table.setPageIndex(2)` is a no-op. Either pass both, or pass `atoms.pagination` (which is its own writeback).' - 'Mixing `state.pagination` AND `atoms.pagination` for the SAME slice. Precedence is `options.atoms[key]` > `options.state[key]` > internal — `state` is silently ignored. Pick one mechanism per slice.' @@ -450,7 +450,7 @@ skills: status: ready description: > Ship-ready optimizations for v9: tree-shake the bundle by registering - ONLY the `_features` you actually use; memoize `_features`, `data`, + ONLY the `features` you actually use; memoize `features`, `data`, and `columns` for stable identity; replace `(state) => state` with narrow selectors or per-slice `useSelector(table.atoms.)` subscriptions; and push state-driven re-renders down the tree with @@ -462,7 +462,7 @@ skills: - |- Tree-shaking: list features explicitly in `tableFeatures({...})` rather than `stockFeatures`. A sort-only table is ~6–7kb vs ~15–20kb for v8's all-in approach. - |- - Reference stability: `_features`, `_rowModels`, `columns`, and `data` should NOT be redefined on every render. Declare at module scope or memoize with `useMemo` / Angular `signal()` / Solid memo. + Reference stability: `features`, `rowModels`, `columns`, and `data` should NOT be redefined on every render. Declare at module scope or memoize with `useMemo` / Angular `signal()` / Solid memo. - |- Default selector trade-off: `(state) => state` matches v8 behavior but forces a re-render on any state change. Narrow it (`(state) => ({ sorting: state.sorting })`) once you've profiled. - |- @@ -483,7 +483,7 @@ skills: - '@tanstack/svelte-table' - '@tanstack/preact-table' tasks: - - "Audit a project's `_features` declarations and remove any feature whose imports aren't actually wired up in column defs / state." + - "Audit a project's `features` declarations and remove any feature whose imports aren't actually wired up in column defs / state." - 'Replace `useTable(opts, (state) => state)` with a narrowed selector when only a subset of state is rendered at the table level.' - 'Wrap a noisy pagination footer (re-renders on every keystroke in a filter) in ` ({ pagination: s.pagination })}>` so it only re-renders on pagination changes.' - 'Move a `RowSelectionCount` component from reading `table.state.rowSelection` to `useSelector(table.atoms.rowSelection)` for the narrowest subscription surface.' @@ -500,8 +500,8 @@ skills: } from '@tanstack/react-table' // Module-scope, stable identity: - const _features = tableFeatures({ rowSortingFeature, rowPaginationFeature }) - const _rowModels = { + const features = tableFeatures({ rowSortingFeature, rowPaginationFeature }) + const rowModels = { sortedRowModel: createSortedRowModel(sortFns), paginatedRowModel: createPaginatedRowModel(), } @@ -509,7 +509,7 @@ skills: function MyTable({ data, columns }) { // ✓ narrow selector — re-renders only when these slices change const table = useTable( - { _features, _rowModels, columns, data }, + { features, rowModels, columns, data }, (state) => ({ sorting: state.sorting, pagination: state.pagination, @@ -540,16 +540,16 @@ skills: // BAD #1: stockFeatures in a sort-only table. // Ships filtering, faceting, grouping, pinning, expanding, sizing, // resizing, visibility, ordering, row-selection, row-pinning code - // none of which is used. ~3x the necessary bundle for `_features`. + // none of which is used. ~3x the necessary bundle for `features`. import { useTable, stockFeatures } from '@tanstack/react-table' - const table = useTable({ _features: stockFeatures, /* ... */ }) + const table = useTable({ features: stockFeatures, /* ... */ }) // BAD #2: unstable references — every render is a new identity. function MyTable({ data, columns }) { - const _features = tableFeatures({ rowSortingFeature }) // new every render + const features = tableFeatures({ rowSortingFeature }) // new every render const opts = { // new every render - _features, - _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, // hopefully stable data, } @@ -576,7 +576,7 @@ skills: } failure_modes: - 'Using `stockFeatures` in production without auditing which features are actually rendered. Defeats the whole reason tree-shaking exists in v9. Replace with an explicit `tableFeatures({...})` listing only what your UI uses.' - - 'Declaring `_features`, `_rowModels`, or `columns` inside the component body without `useMemo`. Internal memoization keys off identity, so a new object every render forces full recomputation.' + - 'Declaring `features`, `rowModels`, or `columns` inside the component body without `useMemo`. Internal memoization keys off identity, so a new object every render forces full recomputation.' - "Putting `data` in `useState` and never memoizing the array literal that produces it. `setData(rows.filter(...))` returns a new array each call — that's fine; the FAQ pitfall is `data={[]}` or `data={rows ?? []}` in JSX, which creates a new identity each render." - 'Leaving `(state) => state` as the selector when only one component cares about one slice. The whole tree re-renders on every state change. Narrow the selector and/or use `` boundaries.' - 'Forgetting that `` still selects from `table.store.state` (the full state). For a single-slice subscription, `useSelector(table.atoms.)` is narrower and skips even constructing a state snapshot.' @@ -641,7 +641,7 @@ skills: } from '@tanstack/react-table' import type { PaginationState, SortingState } from '@tanstack/react-table' - const _features = tableFeatures({ rowSortingFeature, rowPaginationFeature }) + const features = tableFeatures({ rowSortingFeature, rowPaginationFeature }) function MyTable({ columns, data }) { const sortingAtom = useCreateAtom([]) @@ -654,8 +654,8 @@ skills: const pagination = useSelector(paginationAtom) const table = useTable({ - _features, - _rowModels: { + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns), paginatedRowModel: createPaginatedRowModel(), }, @@ -679,7 +679,7 @@ skills: // BAD #1: passing the SAME slice via both `state` and `atoms`. Atoms // win silently and the `state` value is ignored — confusing to debug. useTable({ - _features, _rowModels: {}, + features, rowModels: {}, columns, data, state: { sorting: localSorting }, // ignored onSortingChange: setLocalSorting, // ignored @@ -691,7 +691,7 @@ skills: // resets to initial. (The same trap as `useState(createAtom(...))`.) function MyTable() { const sortingAtom = createAtom([]) // wrong: unstable - useTable({ _features, _rowModels: {}, columns, data, + useTable({ features, rowModels: {}, columns, data, atoms: { sorting: sortingAtom } }) } @@ -761,7 +761,7 @@ skills: from '@tanstack/react-table' import type { PaginationState } from '@tanstack/react-table' - const _features = tableFeatures({ rowPaginationFeature }) + const features = tableFeatures({ rowPaginationFeature }) function ServerTable({ columns }) { const paginationAtom = useCreateAtom({ @@ -776,8 +776,8 @@ skills: }) const table = useTable({ - _features, - _rowModels: {}, // server paginates + features, + rowModels: {}, // server paginates columns, data: dataQuery.data?.rows ?? EMPTY, // EMPTY is module-scope rowCount: dataQuery.data?.rowCount, @@ -815,7 +815,7 @@ skills: - "Missing `rowCount`. `getPageCount()` falls back to `Math.ceil(data.length / pageSize)` which is 1 if the server already paginated. Pager UIs lock at 'Page 1 of 1'." - 'Forgetting to include pagination/sort/filter state in `queryKey`. Query has no other way to know its inputs changed; clicks on the pager update state but the query never refetches.' - 'Skipping `placeholderData: keepPreviousData`. Between pages the table collapses to 0 rows, the row container collapses, and the scroll position jumps.' - - 'Keeping `paginatedRowModel: createPaginatedRowModel()` registered in `_rowModels` for a server-paginated table. The factory ships in your bundle for nothing AND it competes with `manualPagination`.' + - 'Keeping `paginatedRowModel: createPaginatedRowModel()` registered in `rowModels` for a server-paginated table. The factory ships in your bundle for nothing AND it competes with `manualPagination`.' - 'Mixing `state.pagination` + `onPaginationChange` AND `atoms.pagination` for the same slice. `atoms` wins; the `state` plumbing is silently dead. Pick one.' - 'Forgetting `queryClient.invalidateQueries(...)` after mutations. The table is a downstream consumer — it has no way to know the server data changed unless Query tells it.' - 'Recreating `data: dataQuery.data?.rows ?? []` in JSX. The `?? []` produces a new array identity on every render — wrap with a module-scope `const EMPTY: Row[] = []` or `useMemo`.' @@ -874,8 +874,8 @@ skills: function App() { const tableContainerRef = useRef(null) const table = useTable({ - _features: { rowSortingFeature, columnSizingFeature }, - _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features: { rowSortingFeature, columnSizingFeature }, + rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, data, }) return ( @@ -1024,8 +1024,8 @@ skills: // 2. Critical: flatten row type for form path-keys (avoids TS2589) type FormRow = Omit - const _features = tableFeatures({ rowPaginationFeature, columnFilteringFeature }) - const columnHelper = createColumnHelper() + const features = tableFeatures({ rowPaginationFeature, columnFilteringFeature }) + const columnHelper = createColumnHelper() function App() { const form = useAppForm({ @@ -1054,8 +1054,8 @@ skills: void dataLength const table = useTable({ - _features, - _rowModels: { + features, + rowModels: { filteredRowModel: createFilteredRowModel(filterFns), paginatedRowModel: createPaginatedRowModel(), }, diff --git a/_artifacts/scratch/cluster-f-issues-failure-modes.yaml b/_artifacts/scratch/cluster-f-issues-failure-modes.yaml index aed65cb9b0..476441bdfd 100644 --- a/_artifacts/scratch/cluster-f-issues-failure-modes.yaml +++ b/_artifacts/scratch/cluster-f-issues-failure-modes.yaml @@ -55,7 +55,7 @@ issue_findings: wrong_pattern: | // ❌ Common v9 alpha setup — surfaces SubscribeBound warning on every parent rerender function MyTable({ globalFilter }) { - const table = useTable({ _features, data, columns, state: { globalFilter } }) + const table = useTable({ features, data, columns, state: { globalFilter } }) return ( ({ globalFilter: s.globalFilter })}> {() => ...} @@ -69,7 +69,7 @@ issue_findings: function MyTable() { const [globalFilter, setGlobalFilter] = useState('') const table = useTable({ - _features, data, columns, + features, data, columns, state: { globalFilter }, onGlobalFilterChange: setGlobalFilter, }) @@ -128,7 +128,7 @@ issue_findings: import type { ReactTable } from '@tanstack/react-table' columnHelper.accessor('name', { cell: ({ table, row }) => { - const reactTable = table as ReactTable + const reactTable = table as ReactTable return ( s.rowSelection[row.id]}> {(isSelected) => } @@ -341,9 +341,9 @@ issue_findings: // ✅ Move to v9 alpha useTable + Subscribe; opt-in subscription model is React-Compiler-friendly 'use client' import { useTable, tableFeatures, rowSelectionFeature } from '@tanstack/react-table' - const _features = tableFeatures({ rowSelectionFeature }) + const features = tableFeatures({ rowSelectionFeature }) export function DataTable({ columns, data }) { - const table = useTable({ _features, data, columns }) + const table = useTable({ features, data, columns }) return ( ({ rowSelection: s.rowSelection })}> {() =>
} @@ -372,7 +372,7 @@ issue_findings: } correct_pattern: | // ✅ Use v9 alpha — table.Subscribe drives re-renders explicitly - const table = useTable({ _features, data, columns }) + const table = useTable({ features, data, columns }) s.rowSelection}> {() => ( @@ -811,7 +811,7 @@ issue_findings: mechanism: | v9 alpha renames `useReactTable` → `useTable` (and adds a `useLegacyTable` shim). Agents trained on v8 will reach for `useReactTable`. The signature also changes — - `_features` and `_rowModels` are now mandatory configuration, not pre-bundled + `features` and `rowModels` are now mandatory configuration, not pre-bundled defaults. `useReactTable` still exists for back-compat but produces v8-style tables that don't have `.Subscribe`, `.atoms`, or feature composition. wrong_pattern: | @@ -827,10 +827,10 @@ issue_findings: useTable, tableFeatures, sortingFeature, columnFilteringFeature, rowPaginationFeature, } from '@tanstack/react-table' - const _features = tableFeatures({ + const features = tableFeatures({ sortingFeature, columnFilteringFeature, rowPaginationFeature, }) - const table = useTable({ _features, data, columns }) + const table = useTable({ features, data, columns }) source: 'PR #6202 (fix useLegacyTable infinite rerender), useTable.ts source, CHANGELOG history' priority: 'CRITICAL' status: 'active' @@ -840,29 +840,29 @@ issue_findings: mistake: 'Importing pre-bundled getCoreRowModel etc. in v9' mechanism: | In v8, `getCoreRowModel()`, `getSortedRowModel()`, `getFilteredRowModel()` etc. - were standalone factories. In v9, row models are opt-in through `_rowModels` on + were standalone factories. In v9, row models are opt-in through `rowModels` on the table options or auto-installed by features in `tableFeatures()`. Agents will keep emitting v8 imports that either don't exist or aren't wired correctly. wrong_pattern: | // ❌ v8 pattern — won't drive v9 row models const table = useTable({ - _features, + features, data, columns, getCoreRowModel: getCoreRowModel(), getSortedRowModel: getSortedRowModel(), }) correct_pattern: | - // ✅ v9 — row models opt-in via _rowModels or feature inclusion + // ✅ v9 — row models opt-in via rowModels or feature inclusion import { useTable, tableFeatures, sortingFeature, coreRowModelsFeature, sortedRowModelsFeature, } from '@tanstack/react-table' - const _features = tableFeatures({ + const features = tableFeatures({ sortingFeature, coreRowModelsFeature, sortedRowModelsFeature, }) - const table = useTable({ _features, data, columns }) + const table = useTable({ features, data, columns }) source: 'PR #6234 (atoms refactor), v9 alpha package exports' priority: 'CRITICAL' status: 'active' @@ -1065,7 +1065,7 @@ gaps: No issue yet asks this verbatim because v9 is alpha and adoption is small, but every adoption issue shows the same disorientation. The skill needs a 1:1 mapping table from v8 imports to v9 feature/row-model imports, plus a "minimum boilerplate" - example showing _features and the tableFeatures registry. + example showing features and the tableFeatures registry. status: 'open' - skill: 'migrate-v8-to-v9' @@ -1080,7 +1080,7 @@ gaps: question: 'When should I use createTableHook vs useTable directly?' context: | v9 adds `createTableHook` (React/Solid) for ergonomic composition: ``, - pre-configured `_features`, etc. Issues #6199 and #6244 reference it but no skill + pre-configured `features`, etc. Issues #6199 and #6244 reference it but no skill content covers the trade-offs vs the bare `useTable` API. Agents won't know when `createTableHook` is appropriate. status: 'open' diff --git a/_artifacts/skill_spec.md b/_artifacts/skill_spec.md index d576fad21e..ac579b81d3 100644 --- a/_artifacts/skill_spec.md +++ b/_artifacts/skill_spec.md @@ -11,7 +11,7 @@ Headless data-grid library: features, state, and APIs for building powerful, typ | Domain | Description | Skill count | | --------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | ----------: | | **Core foundations** (`core-foundations`) | Setup, column definitions, state management, and customization of built-in feature behavior. State-management is the … | 4 | -| **Row-model features** (`row-model-features`) | Features driven by entries in `_rowModels` — filtering (column+global+faceting+fuzzy), sorting, pagination, grouping,… | 5 | +| **Row-model features** (`row-model-features`) | Features driven by entries in `rowModels` — filtering (column+global+faceting+fuzzy), sorting, pagination, grouping,… | 5 | | **UI-state features** (`ui-state-features`) | Features that are pure UI state — no row model needed. Column layout (visibility/ordering/pinning/sizing/resizing), r… | 3 | | **Framework adapters** (`framework-adapters`) | Per-framework reactivity bindings and rendering integration. Each adapter has its own `table-state` skill; React adds… | 10 | | **Lifecycle** (`lifecycle`) | End-to-end journeys that cross-cut features: getting-started, v8→v9 migration, client-to-server conversion, productio… | 4 | @@ -65,7 +65,7 @@ Headless data-grid library: features, state, and APIs for building powerful, typ | client-side feature richness vs server-side correctness | filtering ↔ sorting ↔ pagination ↔ client-to-server | Agents converting a working client table to use a server endpoint flip `manualPagination` without auditing filtering/sorting consistency | | atomic-state granularity vs API simplicity | state-management ↔ compose-with-tanstack-store ↔ getting-started | Agents default to `state` + `on*Change` because it looks like the v8 idiom, then hit re-render storms or sync issues with Query and patch around them, when the v9 atoms option would have been cleaner. | | React Compiler safety vs render-cost simplicity | react-subscribe-compiler-compat ↔ production-readiness ↔ getting-started | Agents either over-wrap every component in Subscribe (verbose, slow to author) or under-wrap and ship tables that look fine in dev but break under React Compiler in prod | -| tree-shaking via \_features vs ergonomic useLegacyTable | setup ↔ production-readiness ↔ migrate-v8-to-v9 | Agents reach for `useLegacyTable` on v8→v9 migrations and never circle back to declare `_features`, sacrificing the bundle wins that motivated the v9 redesign. | +| tree-shaking via \features vs ergonomic useLegacyTable | setup ↔ production-readiness ↔ migrate-v8-to-v9 | Agents reach for `useLegacyTable` on v8→v9 migrations and never circle back to declare `features`, sacrificing the bundle wins that motivated the v9 redesign. | ## Cross-References @@ -88,7 +88,7 @@ Headless data-grid library: features, state, and APIs for building powerful, typ | `client-to-server` | `compose-with-tanstack-query` | Query is the canonical server-side fetch layer; client-to-server skill expects it | | `client-to-server` | `state-management` | external atoms via atoms option is the cleanest pattern for sharing pagination/sort/filter with Q… | | `production-readiness` | `react-subscribe-compiler-compat` | Subscribe boundaries are a top perf optimization on React | -| `production-readiness` | `setup` | `_features` tree-shaking is decided at setup | +| `production-readiness` | `setup` | `features` tree-shaking is decided at setup | | `compose-with-tanstack-virtual` | `row-expanding` | virtualized + expanding requires careful measurer + getSubRows interaction | | `compose-with-tanstack-virtual` | `column-layout` | virtualized columns interact with sizing and pinning | | `compose-with-tanstack-form` | `row-selection` | editable rows + selection — common together | @@ -125,7 +125,7 @@ From Phase 4 (2026-05-17). Full Q&A is in `domain_map.yaml :: maintainer_intervi 1. **Hallucinating react-table v7 / pre-v9 `@tanstack/[framework]-table` APIs** (CRITICAL). Every major version was a substantial upgrade; agents confidently produce v7/v8 shapes. 2. **Reimplementing what TanStack Table's built-in APIs already provide** (CRITICAL). The #1 tell of AI-written code. TanStack Table IS a state-management coordinator with APIs for nearly every transition (`setSorting`, `toggleSelected`, `nextPage`, `setColumnFilters`, …). -3. **API or state slice "missing" because feature not registered in `_features`** (CRITICAL, v9-specific). v9 is the first version where features must be declared for TS inference and runtime API exposure. +3. **API or state slice "missing" because feature not registered in `features`** (CRITICAL, v9-specific). v9 is the first version where features must be declared for TS inference and runtime API exposure. 4. **Bundling `stockFeatures` or unused features wastes the v9 tree-shake** (HIGH). 5. **Premature `Subscribe`/selector optimization on small tables** (MEDIUM). Advanced state-management patterns are for advanced use cases. diff --git a/_artifacts/skill_tree.yaml b/_artifacts/skill_tree.yaml index 96659f268c..918666c01c 100644 --- a/_artifacts/skill_tree.yaml +++ b/_artifacts/skill_tree.yaml @@ -27,7 +27,7 @@ skills: domain: core-foundations path: packages/table-core/skills/setup/SKILL.md package: packages/table-core - description: Install a table adapter and wire up a first working table with `_features`, `_rowModels`, columns, and data. + description: Install a table adapter and wire up a first working table with `features`, `rowModels`, columns, and data. requires: - state-management - column-definitions @@ -43,7 +43,7 @@ skills: domain: core-foundations path: packages/table-core/skills/column-definitions/SKILL.md package: packages/table-core - description: Define columns with `createColumnHelper()` to extract data and render headers/cells/footers. + description: Define columns with `createColumnHelper()` to extract data and render headers/cells/footers. sources: - TanStack/table:docs/guide/column-defs.md - TanStack/table:docs/guide/columns.md @@ -385,8 +385,8 @@ skills: path: packages/react-table/skills/react/getting-started/SKILL.md package: packages/react-table description: - 'End-to-end first-table journey: install the framework adapter, declare `_features` via `tableFeatures()`, - declare `_rowModels` factories with their *Fns parameters, create a column helper with both `TFeatures` and `TData` generics, + 'End-to-end first-table journey: install the framework adapter, declare `features` via `tableFeatures()`, + declare `rowModels` factories with their *Fns parameters, create a column helper with both `TFeatures` and `TData` generics, instantiate `useTable` / `injectTable` / `createTable`, and render headers + cells with `table.FlexRender` (or `*flexRender*` directives on Angular). New users land here, not on `useLegacyTable`.' requires: @@ -405,8 +405,8 @@ skills: path: packages/vue-table/skills/vue/getting-started/SKILL.md package: packages/vue-table description: - 'End-to-end first-table journey: install the framework adapter, declare `_features` via `tableFeatures()`, - declare `_rowModels` factories with their *Fns parameters, create a column helper with both `TFeatures` and `TData` generics, + 'End-to-end first-table journey: install the framework adapter, declare `features` via `tableFeatures()`, + declare `rowModels` factories with their *Fns parameters, create a column helper with both `TFeatures` and `TData` generics, instantiate `useTable` / `injectTable` / `createTable`, and render headers + cells with `table.FlexRender` (or `*flexRender*` directives on Angular). New users land here, not on `useLegacyTable`.' requires: @@ -425,8 +425,8 @@ skills: path: packages/angular-table/skills/angular/getting-started/SKILL.md package: packages/angular-table description: - 'End-to-end first-table journey: install the framework adapter, declare `_features` via `tableFeatures()`, - declare `_rowModels` factories with their *Fns parameters, create a column helper with both `TFeatures` and `TData` generics, + 'End-to-end first-table journey: install the framework adapter, declare `features` via `tableFeatures()`, + declare `rowModels` factories with their *Fns parameters, create a column helper with both `TFeatures` and `TData` generics, instantiate `useTable` / `injectTable` / `createTable`, and render headers + cells with `table.FlexRender` (or `*flexRender*` directives on Angular). New users land here, not on `useLegacyTable`.' requires: @@ -445,8 +445,8 @@ skills: path: packages/solid-table/skills/solid/getting-started/SKILL.md package: packages/solid-table description: - 'End-to-end first-table journey: install the framework adapter, declare `_features` via `tableFeatures()`, - declare `_rowModels` factories with their *Fns parameters, create a column helper with both `TFeatures` and `TData` generics, + 'End-to-end first-table journey: install the framework adapter, declare `features` via `tableFeatures()`, + declare `rowModels` factories with their *Fns parameters, create a column helper with both `TFeatures` and `TData` generics, instantiate `useTable` / `injectTable` / `createTable`, and render headers + cells with `table.FlexRender` (or `*flexRender*` directives on Angular). New users land here, not on `useLegacyTable`.' requires: @@ -465,8 +465,8 @@ skills: path: packages/svelte-table/skills/svelte/getting-started/SKILL.md package: packages/svelte-table description: - 'End-to-end first-table journey: install the framework adapter, declare `_features` via `tableFeatures()`, - declare `_rowModels` factories with their *Fns parameters, create a column helper with both `TFeatures` and `TData` generics, + 'End-to-end first-table journey: install the framework adapter, declare `features` via `tableFeatures()`, + declare `rowModels` factories with their *Fns parameters, create a column helper with both `TFeatures` and `TData` generics, instantiate `useTable` / `injectTable` / `createTable`, and render headers + cells with `table.FlexRender` (or `*flexRender*` directives on Angular). New users land here, not on `useLegacyTable`.' requires: @@ -485,8 +485,8 @@ skills: path: packages/preact-table/skills/preact/getting-started/SKILL.md package: packages/preact-table description: - 'End-to-end first-table journey: install the framework adapter, declare `_features` via `tableFeatures()`, - declare `_rowModels` factories with their *Fns parameters, create a column helper with both `TFeatures` and `TData` generics, + 'End-to-end first-table journey: install the framework adapter, declare `features` via `tableFeatures()`, + declare `rowModels` factories with their *Fns parameters, create a column helper with both `TFeatures` and `TData` generics, instantiate `useTable` / `injectTable` / `createTable`, and render headers + cells with `table.FlexRender` (or `*flexRender*` directives on Angular). New users land here, not on `useLegacyTable`.' requires: @@ -505,8 +505,8 @@ skills: path: packages/lit-table/skills/lit/getting-started/SKILL.md package: packages/lit-table description: - 'End-to-end first-table journey: install the framework adapter, declare `_features` via `tableFeatures()`, - declare `_rowModels` factories with their *Fns parameters, create a column helper with both `TFeatures` and `TData` generics, + 'End-to-end first-table journey: install the framework adapter, declare `features` via `tableFeatures()`, + declare `rowModels` factories with their *Fns parameters, create a column helper with both `TFeatures` and `TData` generics, instantiate `useTable` / `injectTable` / `createTable`, and render headers + cells with `table.FlexRender` (or `*flexRender*` directives on Angular). New users land here, not on `useLegacyTable`.' requires: @@ -679,7 +679,7 @@ skills: description: "Convert a client-side table to server-side (a.k.a. manual modes). Pattern: pass server data, set `manualSorting` / `manualFiltering` / `manualPagination` / `manualGrouping` / `manualExpanding` for whatever the server now owns, supply - `rowCount` (and/or `pageCount`) so the table can paginate without seeing all rows, and remove the corresponding `_rowModels` + `rowCount` (and/or `pageCount`) so the table can paginate without seeing all rows, and remove the corresponding `rowModels` entries (you don't need `paginatedRowModel` if pagination is server-side). State for the server-managed slices is best owned EITHER via external TanStack Store atoms (passed via `options.atoms`) OR via classic `state` + `on*Change` controlled state — both work. With Query, the atom pattern lets you key your query on the atom and let the table write directly to @@ -700,7 +700,7 @@ skills: description: "Convert a client-side table to server-side (a.k.a. manual modes). Pattern: pass server data, set `manualSorting` / `manualFiltering` / `manualPagination` / `manualGrouping` / `manualExpanding` for whatever the server now owns, supply - `rowCount` (and/or `pageCount`) so the table can paginate without seeing all rows, and remove the corresponding `_rowModels` + `rowCount` (and/or `pageCount`) so the table can paginate without seeing all rows, and remove the corresponding `rowModels` entries (you don't need `paginatedRowModel` if pagination is server-side). State for the server-managed slices is best owned EITHER via external TanStack Store atoms (passed via `options.atoms`) OR via classic `state` + `on*Change` controlled state — both work. With Query, the atom pattern lets you key your query on the atom and let the table write directly to @@ -721,7 +721,7 @@ skills: description: "Convert a client-side table to server-side (a.k.a. manual modes). Pattern: pass server data, set `manualSorting` / `manualFiltering` / `manualPagination` / `manualGrouping` / `manualExpanding` for whatever the server now owns, supply - `rowCount` (and/or `pageCount`) so the table can paginate without seeing all rows, and remove the corresponding `_rowModels` + `rowCount` (and/or `pageCount`) so the table can paginate without seeing all rows, and remove the corresponding `rowModels` entries (you don't need `paginatedRowModel` if pagination is server-side). State for the server-managed slices is best owned EITHER via external TanStack Store atoms (passed via `options.atoms`) OR via classic `state` + `on*Change` controlled state — both work. With Query, the atom pattern lets you key your query on the atom and let the table write directly to @@ -742,7 +742,7 @@ skills: description: "Convert a client-side table to server-side (a.k.a. manual modes). Pattern: pass server data, set `manualSorting` / `manualFiltering` / `manualPagination` / `manualGrouping` / `manualExpanding` for whatever the server now owns, supply - `rowCount` (and/or `pageCount`) so the table can paginate without seeing all rows, and remove the corresponding `_rowModels` + `rowCount` (and/or `pageCount`) so the table can paginate without seeing all rows, and remove the corresponding `rowModels` entries (you don't need `paginatedRowModel` if pagination is server-side). State for the server-managed slices is best owned EITHER via external TanStack Store atoms (passed via `options.atoms`) OR via classic `state` + `on*Change` controlled state — both work. With Query, the atom pattern lets you key your query on the atom and let the table write directly to @@ -763,7 +763,7 @@ skills: description: "Convert a client-side table to server-side (a.k.a. manual modes). Pattern: pass server data, set `manualSorting` / `manualFiltering` / `manualPagination` / `manualGrouping` / `manualExpanding` for whatever the server now owns, supply - `rowCount` (and/or `pageCount`) so the table can paginate without seeing all rows, and remove the corresponding `_rowModels` + `rowCount` (and/or `pageCount`) so the table can paginate without seeing all rows, and remove the corresponding `rowModels` entries (you don't need `paginatedRowModel` if pagination is server-side). State for the server-managed slices is best owned EITHER via external TanStack Store atoms (passed via `options.atoms`) OR via classic `state` + `on*Change` controlled state — both work. With Query, the atom pattern lets you key your query on the atom and let the table write directly to @@ -784,7 +784,7 @@ skills: description: "Convert a client-side table to server-side (a.k.a. manual modes). Pattern: pass server data, set `manualSorting` / `manualFiltering` / `manualPagination` / `manualGrouping` / `manualExpanding` for whatever the server now owns, supply - `rowCount` (and/or `pageCount`) so the table can paginate without seeing all rows, and remove the corresponding `_rowModels` + `rowCount` (and/or `pageCount`) so the table can paginate without seeing all rows, and remove the corresponding `rowModels` entries (you don't need `paginatedRowModel` if pagination is server-side). State for the server-managed slices is best owned EITHER via external TanStack Store atoms (passed via `options.atoms`) OR via classic `state` + `on*Change` controlled state — both work. With Query, the atom pattern lets you key your query on the atom and let the table write directly to @@ -803,8 +803,8 @@ skills: path: packages/react-table/skills/react/production-readiness/SKILL.md package: packages/react-table description: - "Ship-ready optimizations for v9: tree-shake the bundle by registering ONLY the `_features` you actually use; - memoize `_features`, `data`, and `columns` for stable identity; replace `(state) => state` with narrow selectors or per-slice + "Ship-ready optimizations for v9: tree-shake the bundle by registering ONLY the `features` you actually use; + memoize `features`, `data`, and `columns` for stable identity; replace `(state) => state` with narrow selectors or per-slice `useSelector(table.atoms.)` subscriptions; and push state-driven re-renders down the tree with `` (or the standalone `` import) so the expensive table body doesn't re-render every time you toggle a sort indicator. Production builds of the table devtools are also a `/production` import flip — see `compose-with-tanstack-devtools`." @@ -822,8 +822,8 @@ skills: path: packages/vue-table/skills/vue/production-readiness/SKILL.md package: packages/vue-table description: - "Ship-ready optimizations for v9: tree-shake the bundle by registering ONLY the `_features` you actually use; - memoize `_features`, `data`, and `columns` for stable identity; replace `(state) => state` with narrow selectors or per-slice + "Ship-ready optimizations for v9: tree-shake the bundle by registering ONLY the `features` you actually use; + memoize `features`, `data`, and `columns` for stable identity; replace `(state) => state` with narrow selectors or per-slice `useSelector(table.atoms.)` subscriptions; and push state-driven re-renders down the tree with `` (or the standalone `` import) so the expensive table body doesn't re-render every time you toggle a sort indicator. Production builds of the table devtools are also a `/production` import flip — see `compose-with-tanstack-devtools`." @@ -841,8 +841,8 @@ skills: path: packages/angular-table/skills/angular/production-readiness/SKILL.md package: packages/angular-table description: - "Ship-ready optimizations for v9: tree-shake the bundle by registering ONLY the `_features` you actually use; - memoize `_features`, `data`, and `columns` for stable identity; replace `(state) => state` with narrow selectors or per-slice + "Ship-ready optimizations for v9: tree-shake the bundle by registering ONLY the `features` you actually use; + memoize `features`, `data`, and `columns` for stable identity; replace `(state) => state` with narrow selectors or per-slice `useSelector(table.atoms.)` subscriptions; and push state-driven re-renders down the tree with `` (or the standalone `` import) so the expensive table body doesn't re-render every time you toggle a sort indicator. Production builds of the table devtools are also a `/production` import flip — see `compose-with-tanstack-devtools`." @@ -860,8 +860,8 @@ skills: path: packages/solid-table/skills/solid/production-readiness/SKILL.md package: packages/solid-table description: - "Ship-ready optimizations for v9: tree-shake the bundle by registering ONLY the `_features` you actually use; - memoize `_features`, `data`, and `columns` for stable identity; replace `(state) => state` with narrow selectors or per-slice + "Ship-ready optimizations for v9: tree-shake the bundle by registering ONLY the `features` you actually use; + memoize `features`, `data`, and `columns` for stable identity; replace `(state) => state` with narrow selectors or per-slice `useSelector(table.atoms.)` subscriptions; and push state-driven re-renders down the tree with `` (or the standalone `` import) so the expensive table body doesn't re-render every time you toggle a sort indicator. Production builds of the table devtools are also a `/production` import flip — see `compose-with-tanstack-devtools`." @@ -879,8 +879,8 @@ skills: path: packages/svelte-table/skills/svelte/production-readiness/SKILL.md package: packages/svelte-table description: - "Ship-ready optimizations for v9: tree-shake the bundle by registering ONLY the `_features` you actually use; - memoize `_features`, `data`, and `columns` for stable identity; replace `(state) => state` with narrow selectors or per-slice + "Ship-ready optimizations for v9: tree-shake the bundle by registering ONLY the `features` you actually use; + memoize `features`, `data`, and `columns` for stable identity; replace `(state) => state` with narrow selectors or per-slice `useSelector(table.atoms.)` subscriptions; and push state-driven re-renders down the tree with `` (or the standalone `` import) so the expensive table body doesn't re-render every time you toggle a sort indicator. Production builds of the table devtools are also a `/production` import flip — see `compose-with-tanstack-devtools`." @@ -898,8 +898,8 @@ skills: path: packages/preact-table/skills/preact/production-readiness/SKILL.md package: packages/preact-table description: - "Ship-ready optimizations for v9: tree-shake the bundle by registering ONLY the `_features` you actually use; - memoize `_features`, `data`, and `columns` for stable identity; replace `(state) => state` with narrow selectors or per-slice + "Ship-ready optimizations for v9: tree-shake the bundle by registering ONLY the `features` you actually use; + memoize `features`, `data`, and `columns` for stable identity; replace `(state) => state` with narrow selectors or per-slice `useSelector(table.atoms.)` subscriptions; and push state-driven re-renders down the tree with `` (or the standalone `` import) so the expensive table body doesn't re-render every time you toggle a sort indicator. Production builds of the table devtools are also a `/production` import flip — see `compose-with-tanstack-devtools`." diff --git a/docs/framework/angular/angular-table.md b/docs/framework/angular/angular-table.md index e9553238f5..2c9285c837 100644 --- a/docs/framework/angular/angular-table.md +++ b/docs/framework/angular/angular-table.md @@ -4,7 +4,7 @@ title: Angular Table The `@tanstack/angular-table` adapter wraps `@tanstack/table-core` with Angular signals, rendering directives, dependency-injection helpers, and types. `injectTable` supplies Angular reactivity bindings for you, so table atoms can update Angular signals, computed values, effects, and templates. -TanStack Table v9 is explicit about what a table uses. Register features with `_features`, and register client-side row model factories with `_rowModels`. The core row model is included by default, so a basic table can use `_rowModels: {}`. +TanStack Table v9 is explicit about what a table uses. Register features with `features`, and register client-side row model factories with `rowModels`. The core row model is included by default, so a basic table can use `rowModels: {}`. ## Creating a Table @@ -25,9 +25,9 @@ type Person = { age: number } -const _features = tableFeatures({}) +const features = tableFeatures({}) -const columns: Array> = [ +const columns: Array> = [ { accessorKey: 'firstName', header: 'First name', @@ -45,15 +45,15 @@ export class App { readonly data = signal([]) readonly table = injectTable(() => ({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data: this.data(), })) } ``` -For feature-specific row models, register the feature and put the row model factory under `_rowModels`. +For feature-specific row models, register the feature and put the row model factory under `rowModels`. ```ts import { @@ -65,14 +65,14 @@ import { tableFeatures, } from '@tanstack/angular-table' -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, rowSortingFeature, }) const tableOptions = { - _features, - _rowModels: { + features, + rowModels: { paginatedRowModel: createPaginatedRowModel(), sortedRowModel: createSortedRowModel(sortFns), }, @@ -94,7 +94,7 @@ import { type PaginationState, } from '@tanstack/angular-table' -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, }) @@ -105,8 +105,8 @@ export class App { }) readonly table = injectTable(() => ({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data: this.data(), state: { @@ -145,14 +145,14 @@ For `*flexRender`, `*flexRenderHeader`, `*flexRenderFooter`, `flexRenderComponen ## createTableHook -`createTableHook` creates app-specific Angular table helpers. Use it when multiple tables should share `_features`, `_rowModels`, default options, column helpers, and component conventions. +`createTableHook` creates app-specific Angular table helpers. Use it when multiple tables should share `features`, `rowModels`, default options, column helpers, and component conventions. ```ts import { createTableHook, tableFeatures } from '@tanstack/angular-table' const { injectAppTable, createAppColumnHelper } = createTableHook({ - _features: tableFeatures({}), - _rowModels: {}, + features: tableFeatures({}), + rowModels: {}, }) const columnHelper = createAppColumnHelper() diff --git a/docs/framework/angular/guide/migrating.md b/docs/framework/angular/guide/migrating.md index 0ee3ebaa3e..67ada68fdb 100644 --- a/docs/framework/angular/guide/migrating.md +++ b/docs/framework/angular/guide/migrating.md @@ -18,7 +18,7 @@ TanStack Table v9 is a major release that introduces significant architectural i ### 3. Composability -- **`tableOptions`**: New utilities let you compose and share table configurations. Define `_features`, `_rowModels`, and default options once, then reuse them across tables or pass them through `createTableHook`. +- **`tableOptions`**: New utilities let you compose and share table configurations. Define `features`, `rowModels`, and default options once, then reuse them across tables or pass them through `createTableHook`. - **`createTableHook`** (optional, advanced): Create reusable, strongly typed Angular table factories with pre-bound features, row models, default options, and component registries. ### The Good News: Most Upgrades Are Opt-in @@ -28,7 +28,7 @@ While v9 is a significant upgrade, **you don't have to adopt everything at once* - **Don't want to think about tree-shaking yet?** You can start with `stockFeatures` to include most commonly used features. - **Your table markup is largely unchanged.** How you render `
`, ``, ``, `
`, etc. remains the same. -The main change is **how you define a table** with the Angular adapter — specifically the new `_features` and `_rowModels` options. +The main change is **how you define a table** with the Angular adapter — specifically the new `features` and `rowModels` options. --- @@ -36,7 +36,7 @@ The main change is **how you define a table** with the Angular adapter — speci Angular does **not** ship a legacy API. -If you're migrating an Angular project from TanStack Table v8 to v9, you will migrate directly to the v9 Angular adapter APIs (`injectTable`, `_features`, and `_rowModels`). +If you're migrating an Angular project from TanStack Table v8 to v9, you will migrate directly to the v9 Angular adapter APIs (`injectTable`, `features`, and `rowModels`). --- @@ -65,9 +65,9 @@ const v9Table = injectTable(() => ({ ``` > Note: `injectTable` evaluates your initializer whenever any Angular signal read inside of it changes. -> Keep expensive/static values (like `columns`, `_features`, and `_rowModels`) as stable references outside the initializer. +> Keep expensive/static values (like `columns`, `features`, and `rowModels`) as stable references outside the initializer. -### New Required Options: `_features` and `_rowModels` +### New Required Options: `features` and `rowModels` In v9, you must explicitly declare which features and row models your table uses: @@ -87,12 +87,12 @@ import { tableFeatures, } from '@tanstack/angular-table' -const _features = tableFeatures({}) // Empty = core feaFtures only +const features = tableFeatures({}) // Empty = core feaFtures only // Define stable references outside the initializer const v9Table = injectTable(() => ({ - _features, - _rowModels: {}, // Core row model is automatic + features, + rowModels: {}, // Core row model is automatic columns: this.columns, data: this.data(), })) @@ -100,7 +100,7 @@ const v9Table = injectTable(() => ({ --- -## The `_features` Option +## The `features` Option Features control what table functionality is available. In v8, all features were bundled. In v9, you import only what you need. @@ -118,7 +118,7 @@ import { } from '@tanstack/angular-table' // Create a features object (define this outside your injectTable initializer for stable reference) -const _features = tableFeatures({ +const features = tableFeatures({ columnFilteringFeature, rowSortingFeature, rowPaginationFeature, @@ -136,8 +136,8 @@ import { injectTable, stockFeatures } from '@tanstack/angular-table' class TableCmp { readonly table = injectTable(() => ({ - _features: stockFeatures, // All features included - _rowModels: { /* ... */ }, + features: stockFeatures, // All features included + rowModels: { /* ... */ }, columns: this.columns, data: this.data(), })) @@ -165,13 +165,13 @@ class TableCmp { --- -## The `_rowModels` Option +## The `rowModels` Option -Row models are the functions that process your data (filtering, sorting, pagination, etc.). In v9, they're configured via `_rowModels` instead of `get*RowModel` options. +Row models are the functions that process your data (filtering, sorting, pagination, etc.). In v9, they're configured via `rowModels` instead of `get*RowModel` options. ### Migration Mapping -| v8 Option | v9 `_rowModels` Key | v9 Factory Function | +| v8 Option | v9 `rowModels` Key | v9 Factory Function | |-----------|---------------------|---------------------| | `getCoreRowModel()` | (automatic) | Not needed — always included | | `getFilteredRowModel()` | `filteredRowModel` | `createFilteredRowModel(filterFns)` | @@ -201,8 +201,8 @@ import { class TableCmp { readonly table = injectTable(() => ({ - _features, - _rowModels: { + features, + rowModels: { filteredRowModel: createFilteredRowModel(filterFns), sortedRowModel: createSortedRowModel(sortFns), groupedRowModel: createGroupedRowModel(aggregationFns), @@ -253,15 +253,15 @@ import { sortFns, } from '@tanstack/angular-table' -const _features = tableFeatures({ +const features = tableFeatures({ columnFilteringFeature, rowSortingFeature, rowPaginationFeature, }) const v9Table = injectTable(() => ({ - _features, - _rowModels: { + features, + rowModels: { filteredRowModel: createFilteredRowModel(filterFns), sortedRowModel: createSortedRowModel(sortFns), paginatedRowModel: createPaginatedRowModel(), @@ -311,8 +311,8 @@ import { shallow } from '@tanstack/angular-table' class TableCmp { readonly table = injectTable(() => ({ - _features, - _rowModels: { /* ... */ }, + features, + rowModels: { /* ... */ }, columns: this.columns, data: this.data(), })) @@ -342,8 +342,8 @@ import { shallow } from '@tanstack/angular-table' class TableCmp { readonly table = injectTable(() => ({ - _features, - _rowModels: { /* ... */ }, + features, + rowModels: { /* ... */ }, columns: this.columns, data: this.data(), })) @@ -377,8 +377,8 @@ class TableCmp { readonly pagination = signal({ pageIndex: 0, pageSize: 10 }) readonly table = injectTable(() => ({ - _features, - _rowModels: { /* ... */ }, + features, + rowModels: { /* ... */ }, columns: this.columns, data: this.data(), state: { @@ -414,8 +414,8 @@ const columnHelperV8 = createColumnHelper() // v9 import { createColumnHelper, tableFeatures, rowSortingFeature } from '@tanstack/angular-table' -const _features = tableFeatures({ rowSortingFeature }) -const columnHelperV9 = createColumnHelper() +const features = tableFeatures({ rowSortingFeature }) +const columnHelperV9 = createColumnHelper() ``` ### New `columns()` Helper Method @@ -423,7 +423,7 @@ const columnHelperV9 = createColumnHelper() v9 adds a `columns()` helper for better type inference when wrapping column arrays. ```ts -const columnHelper = createColumnHelper() +const columnHelper = createColumnHelper() // Wrap your columns array for better type inference const columns = columnHelper.columns([ @@ -452,8 +452,8 @@ When using `createTableHook`, you get a pre-bound `createAppColumnHelper` that o import { createTableHook, tableFeatures, rowSortingFeature } from '@tanstack/angular-table' const { injectAppTable, createAppColumnHelper } = createTableHook({ - _features: tableFeatures({ rowSortingFeature }), - _rowModels: { /* ... */ }, + features: tableFeatures({ rowSortingFeature }), + rowModels: { /* ... */ }, }) // TFeatures is already bound — only need TData! @@ -513,7 +513,7 @@ import { isDevMode } from '@angular/core'; // Create a reusable options object with features pre-configured const baseOptions = tableOptions({ - _features: tableFeatures({ rowSortingFeature }), + features: tableFeatures({ rowSortingFeature }), debugTable: isDevMode() }) @@ -522,14 +522,14 @@ class TableCmp { ...baseOptions, columns: this.columns, data: this.data(), - _rowModels: {}, + rowModels: {}, })) } ``` ### Composing Partial Options -`tableOptions()` allows you to omit certain required fields (like `data`, `columns`, or `_features`) when creating partial configurations: +`tableOptions()` allows you to omit certain required fields (like `data`, `columns`, or `features`) when creating partial configurations: ```ts import { @@ -545,11 +545,11 @@ import { // Partial options without data or columns const featureOptions = tableOptions({ - _features: tableFeatures({ + features: tableFeatures({ rowSortingFeature, columnFilteringFeature, }), - _rowModels: { + rowModels: { sortedRowModel: createSortedRowModel(sortFns), filteredRowModel: createFilteredRowModel(filterFns), }, @@ -559,9 +559,9 @@ const featureOptions = tableOptions({ ```ts import { injectTable, tableOptions, createPaginatedRowModel } from '@tanstack/angular-table' -// Another partial without _features (inherits from spread) +// Another partial without features (inherits from spread) const paginationDefaults = tableOptions({ - _rowModels: { + rowModels: { paginatedRowModel: createPaginatedRowModel(), }, initialState: { @@ -596,8 +596,8 @@ import { } from '@tanstack/angular-table' const sharedOptions = tableOptions({ - _features: tableFeatures({ rowSortingFeature, rowPaginationFeature }), - _rowModels: { + features: tableFeatures({ rowSortingFeature, rowPaginationFeature }), + rowModels: { sortedRowModel: createSortedRowModel(sortFns), paginatedRowModel: createPaginatedRowModel(), }, @@ -697,19 +697,19 @@ type Row type Cell ``` -### Using `typeof _features` +### Using `typeof features` The easiest way to get the `TFeatures` type is with `typeof`: ```ts -const _features = tableFeatures({ +const features = tableFeatures({ rowSortingFeature, columnFilteringFeature, }) -type MyFeatures = typeof _features +type MyFeatures = typeof features -const columns: ColumnDef[] = [...] +const columns: ColumnDef[] = [...] ``` ### Using `StockFeatures` @@ -734,8 +734,8 @@ The `RowData` type is now more restrictive. ## Migration Checklist -- [ ] Update your table setup to v9 and define `_features` using `tableFeatures()` (or use `stockFeatures`) -- [ ] Migrate `get*RowModel()` options to `_rowModels` +- [ ] Update your table setup to v9 and define `features` using `tableFeatures()` (or use `stockFeatures`) +- [ ] Migrate `get*RowModel()` options to `rowModels` - [ ] Update row model factories to include `Fns` parameters where needed - [ ] Update TypeScript types to include `TFeatures` generic - [ ] Update state access: `table.getState().slice` → `table.atoms..get()` where possible; use `table.state` for full-state/debug reads diff --git a/docs/framework/angular/guide/rendering.md b/docs/framework/angular/guide/rendering.md index d4f5e9190b..00b38f10b1 100644 --- a/docs/framework/angular/guide/rendering.md +++ b/docs/framework/angular/guide/rendering.md @@ -239,8 +239,8 @@ const columns: ColumnDef[] = [ }) export class TableHeadSelectionComponent { readonly table = input.required>(); - // column = input.required>() - // header = input.required>() + // column = input.required>() + // header = input.required>() } ``` diff --git a/docs/framework/angular/guide/table-composition.md b/docs/framework/angular/guide/table-composition.md index f56e9a8520..c4519bd9cc 100644 --- a/docs/framework/angular/guide/table-composition.md +++ b/docs/framework/angular/guide/table-composition.md @@ -47,12 +47,12 @@ export const { injectTableHeaderContext, } = createTableHook({ // Features and row models are shared across all tables - _features: tableFeatures({ + features: tableFeatures({ columnFilteringFeature, rowPaginationFeature, rowSortingFeature, }), - _rowModels: { + rowModels: { sortedRowModel: createSortedRowModel(sortFns), filteredRowModel: createFilteredRowModel(filterFns), paginatedRowModel: createPaginatedRowModel(), @@ -205,7 +205,7 @@ Access header components in the template via `table.appHeader(header)`: - **`table.appHeader(header)`** — utility type functions for templates that wraps a `Header` with the registered `headerComponents` - **`table.appFooter(footer)`** — utility type functions for templates that wraps a `Header` (footer) with the registered `headerComponents` -You do not need to pass `_features` or `_rowModels` — they are inherited from the hook configuration: +You do not need to pass `features` or `rowModels` — they are inherited from the hook configuration: ```ts @Component({ @@ -225,7 +225,7 @@ export class UsersTable { // ... ]) - // No need to specify _features, _rowModels, ... — they come from createTableHook + // No need to specify features, rowModels, ... — they come from createTableHook table = injectAppTable(() => ({ columns: this.columns, data: this.data(), @@ -273,8 +273,8 @@ export const { injectAppTable: injectAdminTable, createAppColumnHelper: createAdminColumnHelper, } = createTableHook({ - _features: tableFeatures({ rowSortingFeature, columnFilteringFeature }), - _rowModels: { /* ... */ }, + features: tableFeatures({ rowSortingFeature, columnFilteringFeature }), + rowModels: { /* ... */ }, cellComponents: { EditableCell, DeleteButton }, }) @@ -283,8 +283,8 @@ export const { injectAppTable: injectReadonlyTable, createAppColumnHelper: createReadonlyColumnHelper, } = createTableHook({ - _features: tableFeatures({ rowSortingFeature }), - _rowModels: { /* ... */ }, + features: tableFeatures({ rowSortingFeature }), + rowModels: { /* ... */ }, cellComponents: { TextCell, NumberCell }, }) ``` diff --git a/docs/framework/angular/guide/table-state.md b/docs/framework/angular/guide/table-state.md index ad6ed33096..c732e7e35a 100644 --- a/docs/framework/angular/guide/table-state.md +++ b/docs/framework/angular/guide/table-state.md @@ -37,17 +37,17 @@ The returned table is also signal-reactive: table state and table APIs are wired ### Feature-based State -State slices are only created for the features that are registered in `_features`. This keeps TanStack Table tree-shakeable and gives TypeScript more accurate state inference. +State slices are only created for the features that are registered in `features`. This keeps TanStack Table tree-shakeable and gives TypeScript more accurate state inference. ```ts -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, rowSortingFeature, }) readonly table = injectTable(() => ({ - _features, - _rowModels: { + features, + rowModels: { paginatedRowModel: createPaginatedRowModel(), sortedRowModel: createSortedRowModel(sortFns), }, @@ -61,7 +61,7 @@ this.table.atoms.sorting.get() // this.table.atoms.rowSelection // TypeScript error unless rowSelectionFeature is registered ``` -If `_features` does not include a feature, its state should not be available in `table.atoms`, `table.store.state`, `initialState`, `state`, or `atoms`. +If `features` does not include a feature, its state should not be available in `table.atoms`, `table.store.state`, `initialState`, `state`, or `atoms`. ### Accessing Table State @@ -99,8 +99,8 @@ import { computed } from '@angular/core' import { shallow } from '@tanstack/angular-table' readonly table = injectTable(() => ({ - _features, - _rowModels: { + features, + rowModels: { paginatedRowModel: createPaginatedRowModel(), }, columns, @@ -161,8 +161,8 @@ If you only need to customize the starting value for some table state, use `init ```ts readonly table = injectTable(() => ({ - _features, - _rowModels: { + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns), paginatedRowModel: createPaginatedRowModel(), }, @@ -219,8 +219,8 @@ readonly pagination = signal({ }) readonly table = injectTable(() => ({ - _features, - _rowModels: { + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns), paginatedRowModel: createPaginatedRowModel(), }, @@ -280,8 +280,8 @@ readonly sorting = signal([ ]) ``` -`TableState` is inferred from the features registered on that table: +`TableState` is inferred from the features registered on that table: ```ts -type MyTableState = TableState +type MyTableState = TableState ``` diff --git a/docs/framework/angular/reference/functions/createTableHook.md b/docs/framework/angular/reference/functions/createTableHook.md index da27713515..2a2c09b91b 100644 --- a/docs/framework/angular/reference/functions/createTableHook.md +++ b/docs/framework/angular/reference/functions/createTableHook.md @@ -50,8 +50,8 @@ helpers without repeating the same feature and component generics. ```ts const { injectAppTable, createAppColumnHelper } = createTableHook({ - _features, - _rowModels: {}, + features, + rowModels: {}, tableComponents: {}, cellComponents: {}, headerComponents: {}, diff --git a/docs/framework/angular/reference/functions/injectTable.md b/docs/framework/angular/reference/functions/injectTable.md index 1ce3c1d731..9edc9f063c 100644 --- a/docs/framework/angular/reference/functions/injectTable.md +++ b/docs/framework/angular/reference/functions/injectTable.md @@ -50,14 +50,14 @@ An Angular-reactive TanStack Table instance. ```ts // Register only the features you need import {tableFeatures, rowPaginationFeature} from '@tanstack/angular-table'; -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, // ...all other features you need }) // Use all table core features import {stockFeatures} from '@tanstack/angular-table'; -const _features = tableFeatures(stockFeatures); +const features = tableFeatures(stockFeatures); ``` 2. Prepare the table columns ```ts @@ -65,13 +65,13 @@ import {ColumnDef} from '@tanstack/angular-table'; type MyData = {} -const columns: ColumnDef[] = [ +const columns: ColumnDef[] = [ // ...column definitions ] // or using createColumnHelper import {createColumnHelper} from '@tanstack/angular-table'; -const columnHelper = createColumnHelper(); +const columnHelper = createColumnHelper(); const columns = columnHelper.columns([ columnHelper.accessor(...), // ...other columns @@ -81,7 +81,7 @@ const columns = columnHelper.columns([ ```ts const table = injectTable(() => { // ...table options, - _features, + features, columns: columns, data: myDataSignal(), }) diff --git a/docs/framework/angular/reference/type-aliases/CreateTableHookResult.md b/docs/framework/angular/reference/type-aliases/CreateTableHookResult.md index 46a2fe22c9..3b85f4e902 100644 --- a/docs/framework/angular/reference/type-aliases/CreateTableHookResult.md +++ b/docs/framework/angular/reference/type-aliases/CreateTableHookResult.md @@ -69,7 +69,7 @@ Defined in: [packages/angular-table/src/helpers/createTableHook.ts:335](https:// ##### tableOptions -() => `Omit`\<`TableOptions`\<`TFeatures`, `TData`\>, `"_features"` \| `"_rowModels"`\> +() => `Omit`\<`TableOptions`\<`TFeatures`, `TData`\>, `"features"` \| `"rowModels"`\> #### Returns diff --git a/docs/framework/lit/guide/table-state.md b/docs/framework/lit/guide/table-state.md index 7a4b8d41a9..e65c658cf9 100644 --- a/docs/framework/lit/guide/table-state.md +++ b/docs/framework/lit/guide/table-state.md @@ -38,17 +38,17 @@ The Lit adapter provides `litReactivity()` to the table's `coreReativityFeature` ### Feature-based State -State slices are only created for the features that are registered in `_features`. This keeps TanStack Table tree-shakeable and gives TypeScript more accurate state inference. +State slices are only created for the features that are registered in `features`. This keeps TanStack Table tree-shakeable and gives TypeScript more accurate state inference. ```ts -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, rowSortingFeature, }) const table = this.tableController.table({ - _features, - _rowModels: { + features, + rowModels: { paginatedRowModel: createPaginatedRowModel(), sortedRowModel: createSortedRowModel(sortFns), }, @@ -62,7 +62,7 @@ table.atoms.sorting.get() // table.atoms.rowSelection // TypeScript error unless rowSelectionFeature is registered ``` -If `_features` does not include a feature, its state should not be available in `table.atoms`, `table.store.state`, `table.state`, `initialState`, `state`, or `atoms`. +If `features` does not include a feature, its state should not be available in `table.atoms`, `table.store.state`, `table.state`, `initialState`, `state`, or `atoms`. ### Accessing Table State @@ -98,8 +98,8 @@ The second argument to `tableController.table(...)` is a TanStack Store selector ```ts const table = this.tableController.table( { - _features, - _rowModels: { + features, + rowModels: { paginatedRowModel: createPaginatedRowModel(), }, columns, @@ -164,8 +164,8 @@ If you only need to customize the starting value for some table state, use `init ```ts const table = this.tableController.table({ - _features, - _rowModels: { + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns), paginatedRowModel: createPaginatedRowModel(), }, @@ -217,7 +217,7 @@ import { type PaginationState, } from '@tanstack/lit-table' -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, }) @@ -227,8 +227,8 @@ const paginationAtom = createAtom({ }) const table = this.tableController.table({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data: this._data, atoms: { @@ -252,8 +252,8 @@ private _sorting: SortingState = [] protected render() { const table = this.tableController.table({ - _features, - _rowModels: { + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns), }, columns, @@ -308,8 +308,8 @@ private _sorting: SortingState = [ ] ``` -`TableState` is inferred from the features registered on that table: +`TableState` is inferred from the features registered on that table: ```ts -type MyTableState = TableState +type MyTableState = TableState ``` diff --git a/docs/framework/lit/lit-table.md b/docs/framework/lit/lit-table.md index f2c8aa35d5..48b15c9e60 100644 --- a/docs/framework/lit/lit-table.md +++ b/docs/framework/lit/lit-table.md @@ -4,7 +4,7 @@ title: Lit Table The `@tanstack/lit-table` adapter wraps `@tanstack/table-core` with a Lit `ReactiveController`, rendering helpers, and types. `TableController` installs the Lit `coreReativityFeature` for you, so TanStack Store atom changes can request Lit host updates. -TanStack Table v9 is explicit about what a table uses. Register features with `_features`, and register client-side row model factories with `_rowModels`. The core row model is included by default, so a basic table can use `_rowModels: {}`. +TanStack Table v9 is explicit about what a table uses. Register features with `features`, and register client-side row model factories with `rowModels`. The core row model is included by default, so a basic table can use `rowModels: {}`. ## Creating a Table @@ -25,9 +25,9 @@ type Person = { age: number } -const _features = tableFeatures({}) +const features = tableFeatures({}) -const columns: Array> = [ +const columns: Array> = [ { accessorKey: 'firstName', header: 'First name', @@ -37,15 +37,15 @@ const columns: Array> = [ @customElement('people-table') export class PeopleTable extends LitElement { - private tableController = new TableController(this) + private tableController = new TableController(this) @state() private data: Person[] = [] protected render() { const table = this.tableController.table({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data: this.data, }) @@ -55,7 +55,7 @@ export class PeopleTable extends LitElement { } ``` -For feature-specific row models, register the feature and put the row model factory under `_rowModels`. +For feature-specific row models, register the feature and put the row model factory under `rowModels`. ```ts import { @@ -67,14 +67,14 @@ import { tableFeatures, } from '@tanstack/lit-table' -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, rowSortingFeature, }) const tableOptions = { - _features, - _rowModels: { + features, + rowModels: { paginatedRowModel: createPaginatedRowModel(), sortedRowModel: createSortedRowModel(sortFns), }, @@ -96,7 +96,7 @@ import { type PaginationState, } from '@tanstack/lit-table' -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, }) @@ -106,8 +106,8 @@ const paginationAtom = createAtom({ }) const table = this.tableController.table({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data: this.data, atoms: { @@ -140,14 +140,14 @@ return html` ## createTableHook -`createTableHook` creates app-specific Lit table helpers. Use it when multiple tables should share `_features`, `_rowModels`, default options, column helpers, and component conventions. +`createTableHook` creates app-specific Lit table helpers. Use it when multiple tables should share `features`, `rowModels`, default options, column helpers, and component conventions. ```ts import { createTableHook, tableFeatures } from '@tanstack/lit-table' const { useAppTable, createAppColumnHelper } = createTableHook({ - _features: tableFeatures({}), - _rowModels: {}, + features: tableFeatures({}), + rowModels: {}, }) const columnHelper = createAppColumnHelper() diff --git a/docs/framework/lit/reference/classes/TableController.md b/docs/framework/lit/reference/classes/TableController.md index 044280e1aa..3c858115ff 100644 --- a/docs/framework/lit/reference/classes/TableController.md +++ b/docs/framework/lit/reference/classes/TableController.md @@ -18,13 +18,13 @@ all other framework adapters (React, Vue, Solid, Svelte, Angular). ```ts @customElement('my-table') class MyTable extends LitElement { - private tableController = new TableController(this) + private tableController = new TableController(this) protected render() { const table = this.tableController.table( { - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, }, @@ -169,7 +169,7 @@ options into the same table instance and expose selected state through ```ts const table = this.tableController.table( - { _features, _rowModels: {}, columns, data }, + { features, rowModels: {}, columns, data }, (state) => ({ sorting: state.sorting }), ) ``` diff --git a/docs/framework/lit/reference/functions/createTableHook.md b/docs/framework/lit/reference/functions/createTableHook.md index 421540a759..6b13f5576d 100644 --- a/docs/framework/lit/reference/functions/createTableHook.md +++ b/docs/framework/lit/reference/functions/createTableHook.md @@ -121,7 +121,7 @@ TFeatures is already known from the createTableHook call; TData is inferred from ##### tableOptions -`Omit`\<`TableOptions`\<`TFeatures`, `TData`\>, `"_features"` \| `"_rowModels"`\> +`Omit`\<`TableOptions`\<`TFeatures`, `TData`\>, `"features"` \| `"rowModels"`\> ##### selector? @@ -299,12 +299,12 @@ export const { useCellContext, useHeaderContext, } = createTableHook({ - _features: tableFeatures({ + features: tableFeatures({ rowPaginationFeature, rowSortingFeature, columnFilteringFeature, }), - _rowModels: { + rowModels: { paginatedRowModel: createPaginatedRowModel(), sortedRowModel: createSortedRowModel(sortFns), filteredRowModel: createFilteredRowModel(filterFns), diff --git a/docs/framework/preact/guide/create-table-hook.md b/docs/framework/preact/guide/create-table-hook.md index c709468e3e..750c78499b 100644 --- a/docs/framework/preact/guide/create-table-hook.md +++ b/docs/framework/preact/guide/create-table-hook.md @@ -37,13 +37,13 @@ export const { useCellContext, useHeaderContext, } = createTableHook({ - _features: tableFeatures({ + features: tableFeatures({ columnFilteringFeature, rowPaginationFeature, rowSortingFeature, }), - _rowModels: { + rowModels: { sortedRowModel: createSortedRowModel(sortFns), filteredRowModel: createFilteredRowModel(filterFns), paginatedRowModel: createPaginatedRowModel(), diff --git a/docs/framework/preact/guide/table-state.md b/docs/framework/preact/guide/table-state.md index 0a78e85266..82e410aac9 100644 --- a/docs/framework/preact/guide/table-state.md +++ b/docs/framework/preact/guide/table-state.md @@ -39,19 +39,19 @@ The Preact adapter mirrors the React adapter. It uses TanStack Store atoms for t ### Feature-based State -State slices are only created for the features that are registered in `_features`. This keeps TanStack Table tree-shakeable and gives TypeScript more accurate state inference. +State slices are only created for the features that are registered in `features`. This keeps TanStack Table tree-shakeable and gives TypeScript more accurate state inference. -For example, if `_features` includes `rowPaginationFeature`, TypeScript exposes pagination state APIs and `table.atoms.pagination`. If `_features` does not include `rowPaginationFeature`, `pagination` should not be available in `table.atoms`, `table.store.state`, `table.state`, `initialState`, `state`, or `atoms`. +For example, if `features` includes `rowPaginationFeature`, TypeScript exposes pagination state APIs and `table.atoms.pagination`. If `features` does not include `rowPaginationFeature`, `pagination` should not be available in `table.atoms`, `table.store.state`, `table.state`, `initialState`, `state`, or `atoms`. ```tsx -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, rowSortingFeature, }) const table = useTable({ - _features, - _rowModels: { + features, + rowModels: { paginatedRowModel: createPaginatedRowModel(), sortedRowModel: createSortedRowModel(sortFns), }, @@ -101,8 +101,8 @@ You can pass your own selector to make `table.state` contain only the reactive s ```tsx const table = useTable( { - _features, - _rowModels: { + features, + rowModels: { paginatedRowModel: createPaginatedRowModel(), }, columns, @@ -121,8 +121,8 @@ For large tables, you can also opt the parent table component out of table-state ```tsx const table = useTable( { - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, }, @@ -141,8 +141,8 @@ Without a `source` prop, `table.Subscribe` subscribes to `table.store` and requi ```tsx const table = useTable( { - _features, - _rowModels: { + features, + rowModels: { filteredRowModel: createFilteredRowModel(filterFns), paginatedRowModel: createPaginatedRowModel(), }, @@ -222,8 +222,8 @@ If you only need to customize the starting value for some table state, use `init ```tsx const table = useTable({ - _features, - _rowModels: { + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns), paginatedRowModel: createPaginatedRowModel(), }, @@ -275,7 +275,7 @@ import { type PaginationState, } from '@tanstack/preact-table' -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, }) @@ -293,8 +293,8 @@ function App() { }) const table = useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data: dataQuery.data?.rows ?? [], rowCount: dataQuery.data?.rowCount, @@ -322,8 +322,8 @@ const [pagination, setPagination] = useState({ }) const table = useTable({ - _features, - _rowModels: { + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns), paginatedRowModel: createPaginatedRowModel(), }, @@ -379,8 +379,8 @@ const [sorting, setSorting] = useState([ ]) ``` -`TableState` is inferred from the features registered on that table: +`TableState` is inferred from the features registered on that table: ```tsx -type MyTableState = TableState +type MyTableState = TableState ``` diff --git a/docs/framework/preact/preact-table.md b/docs/framework/preact/preact-table.md index 85975cd201..2c5c8ca5ab 100644 --- a/docs/framework/preact/preact-table.md +++ b/docs/framework/preact/preact-table.md @@ -4,7 +4,7 @@ title: Preact Table The `@tanstack/preact-table` adapter wraps `@tanstack/table-core` with Preact-specific reactivity, rendering helpers, and types. It installs the Preact `coreReativityFeature` for you, so table state is backed by TanStack Store atoms while Preact components can subscribe through `useTable`, selectors, and `table.Subscribe`. -TanStack Table v9 is explicit about what a table uses. Register features with `_features`, and register client-side row model factories with `_rowModels`. The core row model is included by default, so a basic table can use `_rowModels: {}`. +TanStack Table v9 is explicit about what a table uses. Register features with `features`, and register client-side row model factories with `rowModels`. The core row model is included by default, so a basic table can use `rowModels: {}`. ## Creating a Table @@ -19,9 +19,9 @@ type Person = { age: number } -const _features = tableFeatures({}) +const features = tableFeatures({}) -const columns: Array> = [ +const columns: Array> = [ { accessorKey: 'firstName', header: 'First name', @@ -31,8 +31,8 @@ const columns: Array> = [ function App({ data }: { data: Person[] }) { const table = useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, }) @@ -41,7 +41,7 @@ function App({ data }: { data: Person[] }) { } ``` -For feature-specific row models, register the feature and put the row model factory under `_rowModels`. +For feature-specific row models, register the feature and put the row model factory under `rowModels`. ```tsx import { @@ -53,14 +53,14 @@ import { tableFeatures, } from '@tanstack/preact-table' -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, rowSortingFeature, }) const tableOptions = { - _features, - _rowModels: { + features, + rowModels: { paginatedRowModel: createPaginatedRowModel(), sortedRowModel: createSortedRowModel(sortFns), }, @@ -82,7 +82,7 @@ import { type PaginationState, } from '@tanstack/preact-table' -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, }) @@ -93,8 +93,8 @@ function App({ data }: { data: Person[] }) { }) const table = useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, atoms: { @@ -128,14 +128,14 @@ Use `table.FlexRender` to render column `header`, `cell`, and `footer` definitio ## createTableHook -`createTableHook` creates an app-specific table hook. Use it when multiple tables should share `_features`, `_rowModels`, default options, column helpers, and component conventions. +`createTableHook` creates an app-specific table hook. Use it when multiple tables should share `features`, `rowModels`, default options, column helpers, and component conventions. ```tsx import { createTableHook, tableFeatures } from '@tanstack/preact-table' const { useAppTable, createAppColumnHelper } = createTableHook({ - _features: tableFeatures({}), - _rowModels: {}, + features: tableFeatures({}), + rowModels: {}, }) const columnHelper = createAppColumnHelper() diff --git a/docs/framework/preact/reference/functions/createTableHook.md b/docs/framework/preact/reference/functions/createTableHook.md index f6681de0eb..fe67a43c27 100644 --- a/docs/framework/preact/reference/functions/createTableHook.md +++ b/docs/framework/preact/reference/functions/createTableHook.md @@ -116,7 +116,7 @@ TFeatures is already known from the createTableHook call; TData is inferred from ##### tableOptions -`Omit`\<`TableOptions`\<`TFeatures`, `TData`\>, `"_features"` \| `"_rowModels"`\> +`Omit`\<`TableOptions`\<`TFeatures`, `TData`\>, `"features"` \| `"rowModels"`\> ##### selector? @@ -252,12 +252,12 @@ export const { useCellContext, useHeaderContext, } = createTableHook({ - _features: tableFeatures({ + features: tableFeatures({ rowPaginationFeature, rowSortingFeature, columnFilteringFeature, }), - _rowModels: { + rowModels: { paginatedRowModel: createPaginatedRowModel(), sortedRowModel: createSortedRowModel(sortFns), filteredRowModel: createFilteredRowModel(filterFns), diff --git a/docs/framework/preact/reference/functions/useTable.md b/docs/framework/preact/reference/functions/useTable.md index fa08509d53..931b40504e 100644 --- a/docs/framework/preact/reference/functions/useTable.md +++ b/docs/framework/preact/reference/functions/useTable.md @@ -52,8 +52,8 @@ subscriptions. ```tsx const table = useTable( { - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, }, diff --git a/docs/framework/react/guide/create-table-hook.md b/docs/framework/react/guide/create-table-hook.md index 254b26daa0..eb19d9d9fb 100644 --- a/docs/framework/react/guide/create-table-hook.md +++ b/docs/framework/react/guide/create-table-hook.md @@ -42,13 +42,13 @@ export const { useCellContext, useHeaderContext, } = createTableHook({ - _features: tableFeatures({ + features: tableFeatures({ columnFilteringFeature, rowPaginationFeature, rowSortingFeature, }), - _rowModels: { + rowModels: { sortedRowModel: createSortedRowModel(sortFns), filteredRowModel: createFilteredRowModel(filterFns), paginatedRowModel: createPaginatedRowModel(), @@ -80,8 +80,8 @@ export const { | Export | Description | |--------|-------------| -| `useAppTable` | Hook for creating tables. Merges default options from the hook with per-table options. No need to pass `_features` or `_rowModels`—they come from the hook. | -| `createAppColumnHelper` | Column helper with `TFeatures` pre-bound. Only requires `TData`. Use `createAppColumnHelper()` instead of `createColumnHelper()`. | +| `useAppTable` | Hook for creating tables. Merges default options from the hook with per-table options. No need to pass `features` or `rowModels`—they come from the hook. | +| `createAppColumnHelper` | Column helper with `TFeatures` pre-bound. Only requires `TData`. Use `createAppColumnHelper()` instead of `createColumnHelper()`. | | `useTableContext` | Access the table instance inside `tableComponents`. | | `useCellContext` | Access the cell instance inside `cellComponents`. | | `useHeaderContext` | Access the header instance inside `headerComponents`. | @@ -146,7 +146,7 @@ export function SortIndicator() { ## Using `useAppTable` -Create tables with `useAppTable`—`_features` and `_rowModels` are inherited from the hook: +Create tables with `useAppTable`—`features` and `rowModels` are inherited from the hook: ```tsx const personColumnHelper = createAppColumnHelper() @@ -261,16 +261,16 @@ You can call `createTableHook` multiple times for different parts of your app: // admin-tables.ts export const { useAppTable: useAdminTable, createAppColumnHelper: createAdminColumnHelper } = createTableHook({ - _features: tableFeatures({ rowSortingFeature, columnFilteringFeature, rowSelectionFeature }), - _rowModels: { /* ... */ }, + features: tableFeatures({ rowSortingFeature, columnFilteringFeature, rowSelectionFeature }), + rowModels: { /* ... */ }, cellComponents: { EditableCell, DeleteButton }, }) // readonly-tables.ts export const { useAppTable: useReadonlyTable, createAppColumnHelper: createReadonlyColumnHelper } = createTableHook({ - _features: tableFeatures({ rowSortingFeature }), - _rowModels: { /* ... */ }, + features: tableFeatures({ rowSortingFeature }), + rowModels: { /* ... */ }, cellComponents: { TextCell, NumberCell }, }) ``` diff --git a/docs/framework/react/guide/migrating.md b/docs/framework/react/guide/migrating.md index 092dcfa231..a5f1fba2bd 100644 --- a/docs/framework/react/guide/migrating.md +++ b/docs/framework/react/guide/migrating.md @@ -20,7 +20,7 @@ TanStack Table v9 is a major release that introduces significant architectural i ### 3. Composability -- **`tableOptions`**: New utilities let you compose and share table configurations. Define `_features`, `_rowModels`, and default options once, then reuse them across tables or pass them through `createTableHook`. +- **`tableOptions`**: New utilities let you compose and share table configurations. Define `features`, `rowModels`, and default options once, then reuse them across tables or pass them through `createTableHook`. - **`createTableHook`** (optional, advanced): Create custom table hooks with pre-bound features, row models, and components—similar to TanStack Form's `createFormHook`. Define your table setup once and reuse it across many tables. You don't need this for most use cases; `useTable` is sufficient. ### The Good News: Most Upgrades Are Opt-in @@ -31,7 +31,7 @@ While v9 is a significant upgrade, **you don't have to adopt everything at once* - **Don't want to think about tree-shaking?** Import `stockFeatures` to include all features, just like v8. - **Table markup is largely unchanged.** How you render ``, ``, ``, ` {/snippet} -{#snippet Filter(column: Column, tableRef: SvelteTable)} +{#snippet Filter(column: Column, tableRef: SvelteTable)} {@const firstValue = tableRef .getPreFilteredRowModel() .flatRows[0]?.getValue(column.id)} diff --git a/examples/svelte/row-selection/src/App.svelte b/examples/svelte/row-selection/src/App.svelte index c084e413f4..580917110d 100644 --- a/examples/svelte/row-selection/src/App.svelte +++ b/examples/svelte/row-selection/src/App.svelte @@ -20,7 +20,7 @@ } from '@tanstack/svelte-table' import './index.css' - const _features = tableFeatures({ + const features = tableFeatures({ rowPaginationFeature, rowSelectionFeature, columnFilteringFeature, @@ -44,8 +44,8 @@ // Create table with selector to track specific state const table = createTable( { - _features, - _rowModels: { + features, + rowModels: { filteredRowModel: createFilteredRowModel(filterFns), paginatedRowModel: createPaginatedRowModel(), }, @@ -291,8 +291,8 @@ {#snippet Filter( - column: Column, - table: SvelteTable, + column: Column, + table: SvelteTable, )} {@const firstValue = table .getPreFilteredRowModel() diff --git a/examples/svelte/sorting/src/App.svelte b/examples/svelte/sorting/src/App.svelte index bd2fe5eeec..b5105472ff 100644 --- a/examples/svelte/sorting/src/App.svelte +++ b/examples/svelte/sorting/src/App.svelte @@ -13,11 +13,11 @@ import './index.css' import { makeData, type Person } from './makeData' - const _features = tableFeatures({ + const features = tableFeatures({ rowSortingFeature, }) - const columns: ColumnDef[] = [ + const columns: ColumnDef[] = [ { header: 'Name', footer: (props) => props.column.id, @@ -81,8 +81,8 @@ const table = createTable( { - _features, - _rowModels: { + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns), }, get data() { diff --git a/examples/svelte/sorting/src/tableHelper.svelte.ts b/examples/svelte/sorting/src/tableHelper.svelte.ts index c319d35982..386c35c988 100644 --- a/examples/svelte/sorting/src/tableHelper.svelte.ts +++ b/examples/svelte/sorting/src/tableHelper.svelte.ts @@ -1,5 +1,5 @@ import { rowSortingFeature, tableFeatures } from '@tanstack/svelte-table' -export const _features = tableFeatures({ +export const features = tableFeatures({ rowSortingFeature, }) diff --git a/examples/svelte/sub-components/src/App.svelte b/examples/svelte/sub-components/src/App.svelte index 9be58b4f3f..bd1e5eae1b 100644 --- a/examples/svelte/sub-components/src/App.svelte +++ b/examples/svelte/sub-components/src/App.svelte @@ -12,9 +12,9 @@ import type { Person } from './makeData' import './index.css' - const _features = tableFeatures({ rowExpandingFeature }) + const features = tableFeatures({ rowExpandingFeature }) - const columnHelper = createColumnHelper() + const columnHelper = createColumnHelper() const columns = columnHelper.columns([ columnHelper.display({ @@ -63,8 +63,8 @@ const table = createTable( { debugTable: true, - _features, - _rowModels: { + features, + rowModels: { expandedRowModel: createExpandedRowModel(), }, columns, @@ -77,7 +77,7 @@ ) -{#snippet ExpanderButton(row: Row)} +{#snippet ExpanderButton(row: Row)} {#if row.getCanExpand()} {table .getHeaderGroups() - .map((headerGroup: HeaderGroup) => ( + .map((headerGroup: HeaderGroup) => ( {headerGroup.headers.map( - (header: Header) => ( + (header: Header) => ( {row .getAllCells() - .map((cell: Cell) => ( + .map((cell: Cell) => ( diff --git a/examples/vue/basic-external-state/src/App.tsx b/examples/vue/basic-external-state/src/App.tsx index 1b5bc4400b..650e418f79 100644 --- a/examples/vue/basic-external-state/src/App.tsx +++ b/examples/vue/basic-external-state/src/App.tsx @@ -23,12 +23,12 @@ import type { } from '@tanstack/vue-table' import type { Person } from './makeData' -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, rowSortingFeature, }) -const columnHelper = createColumnHelper() +const columnHelper = createColumnHelper() const columns = columnHelper.columns([ columnHelper.accessor('firstName', { @@ -82,8 +82,8 @@ export default defineComponent({ { key: 'basic-external-state', // needed for devtools debugTable: true, - _features, - _rowModels: { + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns), paginatedRowModel: createPaginatedRowModel(), }, @@ -129,10 +129,10 @@ export default defineComponent({ {table .getHeaderGroups() - .map((headerGroup: HeaderGroup) => ( + .map((headerGroup: HeaderGroup) => ( {headerGroup.headers.map( - (header: Header) => ( + (header: Header) => ( {row .getAllCells() - .map((cell: Cell) => ( + .map((cell: Cell) => ( diff --git a/examples/vue/basic-use-app-table/src/App.vue b/examples/vue/basic-use-app-table/src/App.vue index fd89b0155a..dac31bc9d8 100644 --- a/examples/vue/basic-use-app-table/src/App.vue +++ b/examples/vue/basic-use-app-table/src/App.vue @@ -53,8 +53,8 @@ const defaultData: Array = [ // 3. New in V9! Tell the table which features and row models we want to use. In this case, this will be a basic table with no additional features const { useAppTable, createAppColumnHelper } = createTableHook({ - _features: {}, - _rowModels: {}, // client-side row models. `Core` row model is now included by default, but you can still override it here + features: {}, + rowModels: {}, // client-side row models. `Core` row model is now included by default, but you can still override it here debugTable: true, }) diff --git a/examples/vue/basic-use-table/src/App.tsx b/examples/vue/basic-use-table/src/App.tsx index aa14c4dd6a..e5c705c3a6 100644 --- a/examples/vue/basic-use-table/src/App.tsx +++ b/examples/vue/basic-use-table/src/App.tsx @@ -53,9 +53,9 @@ const defaultData: Array = [ }, ] -const _features = tableFeatures({}) +const features = tableFeatures({}) -const columns: Array> = [ +const columns: Array> = [ { accessorKey: 'firstName', header: 'First Name', @@ -95,8 +95,8 @@ export default defineComponent({ const table = useTable({ key: 'basic-use-table', // needed for devtools debugTable: true, - _features, - _rowModels: {}, + features, + rowModels: {}, columns, get data() { return data.value @@ -115,10 +115,10 @@ export default defineComponent({ {table .getHeaderGroups() - .map((headerGroup: HeaderGroup) => ( + .map((headerGroup: HeaderGroup) => ( {headerGroup.headers.map( - (header: Header) => ( + (header: Header) => ( {table .getRowModel() - .rows.map((row: Row) => ( + .rows.map((row: Row) => ( {row .getAllCells() - .map((cell: Cell) => ( + .map((cell: Cell) => ( @@ -147,10 +147,10 @@ export default defineComponent({ {table .getFooterGroups() - .map((footerGroup: HeaderGroup) => ( + .map((footerGroup: HeaderGroup) => ( {footerGroup.headers.map( - (header: Header) => ( + (header: Header) => ( {table .getHeaderGroups() - .map((headerGroup: HeaderGroup) => ( + .map((headerGroup: HeaderGroup) => ( {headerGroup.headers.map( - (header: Header) => ( + (header: Header) => ( {table .getRowModel() - .rows.map((row: Row) => ( + .rows.map((row: Row) => ( {row .getAllCells() - .map((cell: Cell) => ( + .map((cell: Cell) => ( @@ -133,10 +133,10 @@ export default defineComponent({ {table .getFooterGroups() - .map((footerGroup: HeaderGroup) => ( + .map((footerGroup: HeaderGroup) => ( {footerGroup.headers.map( - (header: Header) => ( + (header: Header) => ( {headerGroup.headers.map( - (header: Header) => ( + (header: Header) => ( {table .getRowModel() - .rows.map((row: Row) => ( + .rows.map((row: Row) => ( {row .getVisibleCells() - .map((cell: Cell) => ( + .map((cell: Cell) => ( @@ -166,10 +166,10 @@ export default defineComponent({ {table .getFooterGroups() - .map((footerGroup: HeaderGroup) => ( + .map((footerGroup: HeaderGroup) => ( {footerGroup.headers.map( - (header: Header) => ( + (header: Header) => ( {table .getHeaderGroups() - .map((headerGroup: HeaderGroup) => ( + .map((headerGroup: HeaderGroup) => ( {headerGroup.headers.map( - (header: Header) => ( + (header: Header) => ( {table .getRowModel() - .rows.map((row: Row) => ( + .rows.map((row: Row) => ( {row .getAllCells() - .map((cell: Cell) => ( + .map((cell: Cell) => ( diff --git a/examples/vue/filters-faceted/src/App.vue b/examples/vue/filters-faceted/src/App.vue index 3bc13726eb..badf4048ae 100644 --- a/examples/vue/filters-faceted/src/App.vue +++ b/examples/vue/filters-faceted/src/App.vue @@ -11,11 +11,11 @@ import { ref } from 'vue' import { makeData } from './makeData' import type { Person } from './makeData' -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, }) -const columnHelper = createColumnHelper() +const columnHelper = createColumnHelper() const INITIAL_PAGE_INDEX = 0 @@ -73,8 +73,8 @@ const columns = ref( const table = useTable( { - _features, - _rowModels: { + features, + rowModels: { paginatedRowModel: createPaginatedRowModel(), }, data, diff --git a/examples/vue/filters-fuzzy/src/App.vue b/examples/vue/filters-fuzzy/src/App.vue index 3bc13726eb..badf4048ae 100644 --- a/examples/vue/filters-fuzzy/src/App.vue +++ b/examples/vue/filters-fuzzy/src/App.vue @@ -11,11 +11,11 @@ import { ref } from 'vue' import { makeData } from './makeData' import type { Person } from './makeData' -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, }) -const columnHelper = createColumnHelper() +const columnHelper = createColumnHelper() const INITIAL_PAGE_INDEX = 0 @@ -73,8 +73,8 @@ const columns = ref( const table = useTable( { - _features, - _rowModels: { + features, + rowModels: { paginatedRowModel: createPaginatedRowModel(), }, data, diff --git a/examples/vue/filters/src/tableHelper.ts b/examples/vue/filters/src/tableHelper.ts index 376c4f8bf4..59c37da05f 100644 --- a/examples/vue/filters/src/tableHelper.ts +++ b/examples/vue/filters/src/tableHelper.ts @@ -23,13 +23,13 @@ export type Person = { export const { appFeatures, createAppColumnHelper, useAppTable } = createTableHook({ - _features: { + features: { columnFilteringFeature, globalFilteringFeature, columnFacetingFeature, rowPaginationFeature, }, - _rowModels: { + rowModels: { filteredRowModel: createFilteredRowModel(filterFns), paginatedRowModel: createPaginatedRowModel(), facetedRowModel: createFacetedRowModel(), diff --git a/examples/vue/grouping/src/App.vue b/examples/vue/grouping/src/App.vue index 3bc13726eb..badf4048ae 100644 --- a/examples/vue/grouping/src/App.vue +++ b/examples/vue/grouping/src/App.vue @@ -11,11 +11,11 @@ import { ref } from 'vue' import { makeData } from './makeData' import type { Person } from './makeData' -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, }) -const columnHelper = createColumnHelper() +const columnHelper = createColumnHelper() const INITIAL_PAGE_INDEX = 0 @@ -73,8 +73,8 @@ const columns = ref( const table = useTable( { - _features, - _rowModels: { + features, + rowModels: { paginatedRowModel: createPaginatedRowModel(), }, data, diff --git a/examples/vue/kitchen-sink/src/App.vue b/examples/vue/kitchen-sink/src/App.vue index 5e49648237..af5f1b4442 100644 --- a/examples/vue/kitchen-sink/src/App.vue +++ b/examples/vue/kitchen-sink/src/App.vue @@ -164,8 +164,8 @@ const data = ref(makeData(1_000)) const table = useTable( { key: 'kitchen-sink', // needed for devtools - _features: stockFeatures, - _rowModels: { + features: stockFeatures, + rowModels: { expandedRowModel: createExpandedRowModel(), filteredRowModel: createFilteredRowModel({ ...filterFns, diff --git a/examples/vue/pagination/src/App.vue b/examples/vue/pagination/src/App.vue index 3bc13726eb..badf4048ae 100644 --- a/examples/vue/pagination/src/App.vue +++ b/examples/vue/pagination/src/App.vue @@ -11,11 +11,11 @@ import { ref } from 'vue' import { makeData } from './makeData' import type { Person } from './makeData' -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, }) -const columnHelper = createColumnHelper() +const columnHelper = createColumnHelper() const INITIAL_PAGE_INDEX = 0 @@ -73,8 +73,8 @@ const columns = ref( const table = useTable( { - _features, - _rowModels: { + features, + rowModels: { paginatedRowModel: createPaginatedRowModel(), }, data, diff --git a/examples/vue/row-pinning/src/App.vue b/examples/vue/row-pinning/src/App.vue index 3bc13726eb..badf4048ae 100644 --- a/examples/vue/row-pinning/src/App.vue +++ b/examples/vue/row-pinning/src/App.vue @@ -11,11 +11,11 @@ import { ref } from 'vue' import { makeData } from './makeData' import type { Person } from './makeData' -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, }) -const columnHelper = createColumnHelper() +const columnHelper = createColumnHelper() const INITIAL_PAGE_INDEX = 0 @@ -73,8 +73,8 @@ const columns = ref( const table = useTable( { - _features, - _rowModels: { + features, + rowModels: { paginatedRowModel: createPaginatedRowModel(), }, data, diff --git a/examples/vue/row-selection/src/App.vue b/examples/vue/row-selection/src/App.vue index a6622a7036..f694cfb1c9 100644 --- a/examples/vue/row-selection/src/App.vue +++ b/examples/vue/row-selection/src/App.vue @@ -11,11 +11,11 @@ import { ref } from 'vue' import IndeterminateCheckbox from './IndeterminateCheckbox.vue' import { makeData, Person } from './makeData' -const _features = tableFeatures({ +const features = tableFeatures({ rowSelectionFeature, }) -const columnHelper = createColumnHelper() +const columnHelper = createColumnHelper() const columns = columnHelper.columns([ columnHelper.display({ @@ -107,8 +107,8 @@ const toggleRowSelection = () => { const table = useTable( { key: 'row-selection', // needed for devtools - _features, - _rowModels: {}, + features, + rowModels: {}, data, columns, debugTable: true, diff --git a/examples/vue/sorting/src/App.vue b/examples/vue/sorting/src/App.vue index 6c600ebb33..1e995da354 100644 --- a/examples/vue/sorting/src/App.vue +++ b/examples/vue/sorting/src/App.vue @@ -12,11 +12,11 @@ import { h, ref } from 'vue' import { makeData } from './makeData' import type { Person } from './makeData' -const _features = tableFeatures({ +const features = tableFeatures({ rowSortingFeature, }) -const columnHelper = createColumnHelper() +const columnHelper = createColumnHelper() const columns = columnHelper.columns([ columnHelper.accessor('firstName', { @@ -59,8 +59,8 @@ const stressTest = () => { const table = useTable( { - _features, - _rowModels: { + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns), }, data, diff --git a/examples/vue/sub-components/src/App.vue b/examples/vue/sub-components/src/App.vue index 8fd71521d9..299e766f80 100644 --- a/examples/vue/sub-components/src/App.vue +++ b/examples/vue/sub-components/src/App.vue @@ -10,8 +10,8 @@ import type { Row } from '@tanstack/vue-table' import type { Person } from './makeData' const { appFeatures, createAppColumnHelper, useAppTable } = createTableHook({ - _features: { rowExpandingFeature }, - _rowModels: { + features: { rowExpandingFeature }, + rowModels: { expandedRowModel: createExpandedRowModel(), }, }) diff --git a/examples/vue/virtualized-columns/src/App.vue b/examples/vue/virtualized-columns/src/App.vue index 33c60ebdc2..0323bd8a9a 100644 --- a/examples/vue/virtualized-columns/src/App.vue +++ b/examples/vue/virtualized-columns/src/App.vue @@ -15,7 +15,7 @@ import { makeColumns, makeData } from './makeData' import type { ComponentPublicInstance } from 'vue' import type { Person } from './makeData' -const _features = tableFeatures({ +const features = tableFeatures({ columnSizingFeature, columnVisibilityFeature, rowSortingFeature, @@ -46,8 +46,8 @@ function stressTestColumns() { } const table = useTable({ - _features, - _rowModels: { + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns), }, get columns() { diff --git a/examples/vue/virtualized-infinite-scrolling/src/App.vue b/examples/vue/virtualized-infinite-scrolling/src/App.vue index 869f705c96..ce626bb323 100644 --- a/examples/vue/virtualized-infinite-scrolling/src/App.vue +++ b/examples/vue/virtualized-infinite-scrolling/src/App.vue @@ -20,12 +20,12 @@ import type { Person, PersonApiResponse } from './makeData' const fetchSize = 50 const isDev = import.meta.env.DEV -const _features = tableFeatures({ +const features = tableFeatures({ columnSizingFeature, rowSortingFeature, }) -const columnHelper = createColumnHelper() +const columnHelper = createColumnHelper() const columns = columnHelper.columns([ columnHelper.accessor('id', { @@ -113,8 +113,8 @@ onMounted(() => { }) const table = useTable({ - _features, - _rowModels: { + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns), }, get data() { diff --git a/examples/vue/virtualized-rows/src/App.vue b/examples/vue/virtualized-rows/src/App.vue index 310ce17cb3..1263d9d586 100644 --- a/examples/vue/virtualized-rows/src/App.vue +++ b/examples/vue/virtualized-rows/src/App.vue @@ -16,7 +16,7 @@ import type { ColumnDef } from '@tanstack/vue-table' import type { ComponentPublicInstance } from 'vue' import type { Person } from './makeData' -const _features = tableFeatures({ +const features = tableFeatures({ columnSizingFeature, rowSortingFeature, }) @@ -61,7 +61,7 @@ function handleDebounceSearch(ev: Event) { }, 300) } -const columns = computed>>(() => [ +const columns = computed>>(() => [ { accessorKey: 'id', header: 'ID', @@ -100,8 +100,8 @@ const columns = computed>>(() => [ ]) const table = useTable({ - _features, - _rowModels: { + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns), }, get data() { diff --git a/examples/vue/with-tanstack-form/src/App.vue b/examples/vue/with-tanstack-form/src/App.vue index 3bc13726eb..badf4048ae 100644 --- a/examples/vue/with-tanstack-form/src/App.vue +++ b/examples/vue/with-tanstack-form/src/App.vue @@ -11,11 +11,11 @@ import { ref } from 'vue' import { makeData } from './makeData' import type { Person } from './makeData' -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, }) -const columnHelper = createColumnHelper() +const columnHelper = createColumnHelper() const INITIAL_PAGE_INDEX = 0 @@ -73,8 +73,8 @@ const columns = ref( const table = useTable( { - _features, - _rowModels: { + features, + rowModels: { paginatedRowModel: createPaginatedRowModel(), }, data, diff --git a/examples/vue/with-tanstack-query/src/App.tsx b/examples/vue/with-tanstack-query/src/App.tsx index d09c60e31d..333152e2d7 100644 --- a/examples/vue/with-tanstack-query/src/App.tsx +++ b/examples/vue/with-tanstack-query/src/App.tsx @@ -12,11 +12,11 @@ import { fetchData } from './fetchData' import type { Person } from './fetchData' import type { Cell, Header, HeaderGroup, Row } from '@tanstack/vue-table' -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, }) -const columnHelper = createColumnHelper() +const columnHelper = createColumnHelper() const columns = columnHelper.columns([ columnHelper.accessor('firstName', { @@ -72,8 +72,8 @@ export default defineComponent({ }) const table = useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data: tableData, rowCount, @@ -91,10 +91,10 @@ export default defineComponent({ {table .getHeaderGroups() - .map((headerGroup: HeaderGroup) => ( + .map((headerGroup: HeaderGroup) => ( {headerGroup.headers.map( - (header: Header) => ( + (header: Header) => ( {table .getRowModel() - .rows.map((row: Row) => ( + .rows.map((row: Row) => ( {row .getAllCells() - .map((cell: Cell) => ( + .map((cell: Cell) => ( diff --git a/packages/angular-table/skills/angular/angular-rendering-directives/SKILL.md b/packages/angular-table/skills/angular/angular-rendering-directives/SKILL.md index aa197dfbe4..16b5d98fa3 100644 --- a/packages/angular-table/skills/angular/angular-rendering-directives/SKILL.md +++ b/packages/angular-table/skills/angular/angular-rendering-directives/SKILL.md @@ -155,7 +155,7 @@ returning component classes with `input()` slots). The 90% case — return a value, render it. ```ts -const columns: Array> = [ +const columns: Array> = [ { accessorKey: 'firstName', header: 'First name', @@ -189,7 +189,7 @@ export class SelectAllComponent { readonly table = input.required>() } -const columns: Array> = [ +const columns: Array> = [ { id: 'select', header: () => SelectAllComponent, @@ -297,8 +297,8 @@ column defs short and typed. ```ts export const { injectAppTable, createAppColumnHelper } = createTableHook({ - _features: tableFeatures({ rowSortingFeature }), - _rowModels: { + features: tableFeatures({ rowSortingFeature }), + rowModels: { /* … */ }, tableComponents: { PaginationControls, RowCount }, diff --git a/packages/angular-table/skills/angular/angular-rendering-directives/references/content-shapes.md b/packages/angular-table/skills/angular/angular-rendering-directives/references/content-shapes.md index d55067b122..93c576817d 100644 --- a/packages/angular-table/skills/angular/angular-rendering-directives/references/content-shapes.md +++ b/packages/angular-table/skills/angular/angular-rendering-directives/references/content-shapes.md @@ -20,7 +20,7 @@ read signals, and access DI tokens from within `cell: () => …`. The most common cell — read the value and return it. ```ts -const columns: Array> = [ +const columns: Array> = [ { accessorKey: 'firstName', header: 'First name', @@ -128,7 +128,7 @@ export class SelectAllComponent { readonly table = input.required>() } -const columns: Array> = [ +const columns: Array> = [ { id: 'select', header: () => SelectAllComponent, diff --git a/packages/angular-table/skills/angular/angular-rendering-directives/references/create-table-hook-registries.md b/packages/angular-table/skills/angular/angular-rendering-directives/references/create-table-hook-registries.md index fc945f4b08..2493748231 100644 --- a/packages/angular-table/skills/angular/angular-rendering-directives/references/create-table-hook-registries.md +++ b/packages/angular-table/skills/angular/angular-rendering-directives/references/create-table-hook-registries.md @@ -26,8 +26,8 @@ export const { injectTableCellContext, injectTableHeaderContext, } = createTableHook({ - _features: tableFeatures({ rowSortingFeature }), - _rowModels: { + features: tableFeatures({ rowSortingFeature }), + rowModels: { /* … */ }, tableComponents: { PaginationControls, RowCount }, diff --git a/packages/angular-table/skills/angular/angular-rendering-directives/references/flex-render-component-options.md b/packages/angular-table/skills/angular/angular-rendering-directives/references/flex-render-component-options.md index 59299caac0..fee80afb37 100644 --- a/packages/angular-table/skills/angular/angular-rendering-directives/references/flex-render-component-options.md +++ b/packages/angular-table/skills/angular/angular-rendering-directives/references/flex-render-component-options.md @@ -8,7 +8,7 @@ callbacks, a custom injector, or Angular v20+ `bindings` / `directives`, import { flexRenderComponent, type ColumnDef } from '@tanstack/angular-table' import { EditableCell } from './editable-cell' -const columns: Array> = [ +const columns: Array> = [ { accessorKey: 'firstName', cell: ({ getValue, row, column, table }) => diff --git a/packages/angular-table/skills/angular/client-to-server/SKILL.md b/packages/angular-table/skills/angular/client-to-server/SKILL.md index e08af83b61..a2b70237f6 100644 --- a/packages/angular-table/skills/angular/client-to-server/SKILL.md +++ b/packages/angular-table/skills/angular/client-to-server/SKILL.md @@ -3,7 +3,7 @@ name: angular/client-to-server description: > Convert an Angular Table v9 from client-side to server-side processing. Flip `manualPagination` / `manualSorting` / `manualFiltering` / `manualGrouping` / `manualExpanding` - for the slices the server now owns; drop the corresponding `_rowModels` row-model factories the + for the slices the server now owns; drop the corresponding `rowModels` row-model factories the server replaces; supply `rowCount` (server total) so pagination computes correctly; hoist `pagination` / `sorting` / `columnFilters` / `globalFilter` to Angular signals with `state` + `on[State]Change`; fetch via `rxResource` / `httpResource` / `@tanstack/angular-query`; preserve @@ -44,7 +44,7 @@ For each slice the server now owns: 1. **Flip `manualX: true`** in table options. This tells the table "don't process this on the client — trust the data you receive." -2. **Drop the matching client-side row-model factory** from `_rowModels` +2. **Drop the matching client-side row-model factory** from `rowModels` (or keep it if you still want the feature's _state_ but no client recomputation — see §3). 3. **Hoist the slice to an Angular signal**, control it via `state.x` + @@ -104,13 +104,13 @@ import { type SortingState, } from '@tanstack/angular-table' -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, rowSortingFeature, globalFilteringFeature, }) -const columnHelper = createColumnHelper() +const columnHelper = createColumnHelper() type TodoResponse = { items: Array; totalCount: number } @@ -186,7 +186,7 @@ export class App { }, }) - readonly columns: Array> = [ + readonly columns: Array> = [ columnHelper.accessor('id', { header: 'Id', cell: (i) => i.getValue() }), columnHelper.accessor('title', { header: 'Title', @@ -202,8 +202,8 @@ export class App { readonly table = injectTable(() => { const data = this.dataWithLatest() return { - _features, - _rowModels: {}, // ← dropped paginatedRowModel, sortedRowModel, filteredRowModel + features, + rowModels: {}, // ← dropped paginatedRowModel, sortedRowModel, filteredRowModel columns: this.columns, data: data.items, getRowId: (row) => String(row.id), @@ -245,7 +245,7 @@ export class App { ### What changed from the client-side version -- `_rowModels: {}` — no `paginatedRowModel`, no `sortedRowModel`, no +- `rowModels: {}` — no `paginatedRowModel`, no `sortedRowModel`, no `filteredRowModel`. The server is the source of truth. - `manualPagination` / `manualSorting` / `manualFiltering: true`. - `rowCount: data.totalCount` — required for correct `getPageCount()` and the @@ -361,7 +361,7 @@ edits (toggle the flag around the update). ### 1. (CRITICAL) Flipping `manualPagination: true` but keeping -`paginatedRowModel` in `_rowModels` +`paginatedRowModel` in `rowModels` The client row-model factory will re-paginate the (already-paginated) data, chopping the visible rows down to the first `pageSize` of the page slice. @@ -448,10 +448,10 @@ the new filtered result set only has 2 pages. They have to manually click back to page 1. Always reset `pageIndex` to 0 in `onGlobalFilterChange` / `onColumnFiltersChange`. -### 11. (MEDIUM) Treating `_rowModels: {}` as "no row models work" +### 11. (MEDIUM) Treating `rowModels: {}` as "no row models work" Core row model is always automatic. `table.getRowModel().rows` returns the -data array as `Row<...>` objects no matter what — `_rowModels: {}` just means +data array as `Row<...>` objects no matter what — `rowModels: {}` just means no client-side processing on top. --- diff --git a/packages/angular-table/skills/angular/compose-with-tanstack-query/SKILL.md b/packages/angular-table/skills/angular/compose-with-tanstack-query/SKILL.md index 93ff5bdece..d9d935848f 100644 --- a/packages/angular-table/skills/angular/compose-with-tanstack-query/SKILL.md +++ b/packages/angular-table/skills/angular/compose-with-tanstack-query/SKILL.md @@ -5,7 +5,7 @@ description: > Key the query on the controlled table state that drives the request (pagination, sorting, filters); use `placeholderData: keepPreviousData` to avoid a "0 rows flash" between pages; set `manualPagination` / `manualSorting` / `manualFiltering` for the slices the server owns; - drop the matching client `_rowModels` factories; pass `rowCount` from the server response; + drop the matching client `rowModels` factories; pass `rowCount` from the server response; set `getRowId` for stable selection across refetches; hoist controlled slices to Angular signals + `state` + `on[State]Change`. Alternative — `rxResource` / `httpResource` if you don't want to add the Query dependency (see `client-to-server`). @@ -89,13 +89,13 @@ import { type SortingState, } from '@tanstack/angular-table' -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, rowSortingFeature, globalFilteringFeature, }) -const columnHelper = createColumnHelper() +const columnHelper = createColumnHelper() type TodoResponse = { items: Array; totalCount: number } @@ -153,7 +153,7 @@ export class App { })) // 3. Stable column defs (module-scope-able) - readonly columns: Array> = [ + readonly columns: Array> = [ columnHelper.accessor('id', { header: 'Id', cell: (i) => i.getValue() }), columnHelper.accessor('title', { header: 'Title', @@ -169,8 +169,8 @@ export class App { readonly table = injectTable(() => { const data = this.todosQuery.data() ?? { items: [], totalCount: 0 } return { - _features, - _rowModels: {}, // ← dropped paginatedRowModel / sortedRowModel / filteredRowModel + features, + rowModels: {}, // ← dropped paginatedRowModel / sortedRowModel / filteredRowModel columns: this.columns, data: data.items, getRowId: (row) => String(row.id), @@ -219,7 +219,7 @@ For server-driven Table + Query to work correctly: during refetches. Without it, `todosQuery.data()` becomes `undefined` mid-fetch, your table shows 0 rows for a frame, the user notices. 3. **`manualPagination` / `manualSorting` / `manualFiltering: true`** for - slices the server owns + **drop the matching `_rowModels` factories** so + slices the server owns + **drop the matching `rowModels` factories** so the table doesn't re-process the data the server already filtered/sorted/paged. 4. **`rowCount: data.totalCount`** (or `pageCount`) so `getPageCount()` computes correctly under `manualPagination`. @@ -412,10 +412,10 @@ how many rows exist — pass it. ```ts // ❌ Double-processes the data manualPagination: true, -_rowModels: { paginatedRowModel: createPaginatedRowModel() }, // re-paginates server page +rowModels: { paginatedRowModel: createPaginatedRowModel() }, // re-paginates server page // ✅ -_rowModels: {} // (or just keep the ones still client-side) +rowModels: {} // (or just keep the ones still client-side) ``` Same applies to `sortedRowModel` under `manualSorting` and `filteredRowModel` diff --git a/packages/angular-table/skills/angular/compose-with-tanstack-store/SKILL.md b/packages/angular-table/skills/angular/compose-with-tanstack-store/SKILL.md index 71f5f295a5..f50a6633ed 100644 --- a/packages/angular-table/skills/angular/compose-with-tanstack-store/SKILL.md +++ b/packages/angular-table/skills/angular/compose-with-tanstack-store/SKILL.md @@ -49,7 +49,7 @@ Every TanStack Table instance exposes its state at three layers: | `table.state` | Readonly flat proxy | Reads from slice atoms | Full-state JSON/debug output | | `table.store` | Readonly flat `Store` | Backed by an Angular `computed` | Low-level flat store access; rare | -All three are populated only for **registered features** (`_features`). All +All three are populated only for **registered features** (`features`). All three are signal-backed via `angularReactivity(injector)`: `createReadonlyAtom` → Angular `computed`, `createWritableAtom` → Angular `signal`, subscriptions bridged through `toObservable(computed(signal), { @@ -85,7 +85,7 @@ import { type SortingState, } from '@tanstack/angular-table' -const _features = tableFeatures({ rowPaginationFeature, rowSortingFeature }) +const features = tableFeatures({ rowPaginationFeature, rowSortingFeature }) // Module-scope (or app-scope) shared atoms export const paginationStore = new Store({ @@ -98,8 +98,8 @@ export const sortingStore = new Store([]) @Component({...}) export class App { readonly table = injectTable(() => ({ - _features, - _rowModels: { /* … */ }, + features, + rowModels: { /* … */ }, columns, data: this.data(), atoms: { @@ -151,7 +151,7 @@ import { type PaginationState, } from '@tanstack/angular-table' -const _features = tableFeatures({ rowPaginationFeature }) +const features = tableFeatures({ rowPaginationFeature }) // Shared, app-scope atom export const paginationStore = new Store({ @@ -187,8 +187,8 @@ export class PageRoute { } readonly table = injectTable(() => ({ - _features, - _rowModels: { + features, + rowModels: { /* … */ }, columns, @@ -238,8 +238,8 @@ export const sharedFilter = new Store(null) // Table A readonly tableA = injectTable(() => ({ - _features: tableFeatures({ globalFilteringFeature }), - _rowModels: { filteredRowModel: createFilteredRowModel(filterFns) }, + features: tableFeatures({ globalFilteringFeature }), + rowModels: { filteredRowModel: createFilteredRowModel(filterFns) }, columns: columnsA, data: this.dataA(), atoms: { globalFilter: sharedFilter }, @@ -247,8 +247,8 @@ readonly tableA = injectTable(() => ({ // Table B (separate component, same module) readonly tableB = injectTable(() => ({ - _features: tableFeatures({ globalFilteringFeature }), - _rowModels: { filteredRowModel: createFilteredRowModel(filterFns) }, + features: tableFeatures({ globalFilteringFeature }), + rowModels: { filteredRowModel: createFilteredRowModel(filterFns) }, columns: columnsB, data: this.dataB(), atoms: { globalFilter: sharedFilter }, diff --git a/packages/angular-table/skills/angular/compose-with-tanstack-virtual/SKILL.md b/packages/angular-table/skills/angular/compose-with-tanstack-virtual/SKILL.md index 849490216e..1a3a7e6fe8 100644 --- a/packages/angular-table/skills/angular/compose-with-tanstack-virtual/SKILL.md +++ b/packages/angular-table/skills/angular/compose-with-tanstack-virtual/SKILL.md @@ -66,7 +66,7 @@ import { } from '@tanstack/angular-table' import { injectVirtualizer } from '@tanstack/angular-virtual' -const _features = tableFeatures({}) +const features = tableFeatures({}) @Component({ selector: 'app-virtual-table', @@ -81,8 +81,8 @@ export class VirtualTable { viewChild.required>('scroll') readonly table = injectTable(() => ({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data: this.data(), getRowId: (row) => row.id, @@ -216,8 +216,8 @@ caches that, scrollbar adjusts.) Combine with `rowExpandingFeature` for "click to expand details": -- Register `rowExpandingFeature` in `_features` and - `expandedRowModel: createExpandedRowModel()` in `_rowModels`. +- Register `rowExpandingFeature` in `features` and + `expandedRowModel: createExpandedRowModel()` in `rowModels`. - Use `table.getExpandedRowModel().rows` (or `getRowModel().rows`, which already includes expansion under `paginateExpandedRows: true` semantics — see `tanstack-table/core/row-expanding`). diff --git a/packages/angular-table/skills/angular/getting-started/SKILL.md b/packages/angular-table/skills/angular/getting-started/SKILL.md index 7378c8d649..26667e6d7e 100644 --- a/packages/angular-table/skills/angular/getting-started/SKILL.md +++ b/packages/angular-table/skills/angular/getting-started/SKILL.md @@ -2,8 +2,8 @@ name: angular/getting-started description: > End-to-end first-table journey for TanStack Table v9 in Angular: install - `@tanstack/angular-table`, declare `_features` with `tableFeatures()`, register row-model - factories under `_rowModels` with explicit `*Fns` parameters, build columns with the + `@tanstack/angular-table`, declare `features` with `tableFeatures()`, register row-model + factories under `rowModels` with explicit `*Fns` parameters, build columns with the `TFeatures, TData` generic order, call `injectTable(() => ({...}))` from an injection context, and render with `FlexRender` / `*flexRenderHeader` / `*flexRenderCell` / `*flexRenderFooter`. Covers the minimum-viable signal-backed table plus the upgrade path to sorting + filtering + @@ -31,8 +31,8 @@ sources: > Goal: from zero to a working signal-backed, sorted + paginated, type-safe > table in Angular ≥19. > -> v9 is **explicit**: tell the table which features you want with `_features`, -> tell it which row models you want with `_rowModels`. That explicitness is what +> v9 is **explicit**: tell the table which features you want with `features`, +> tell it which row models you want with `rowModels`. That explicitness is what > makes the v9 bundle tree-shakeable. --- @@ -68,11 +68,11 @@ type Person = { age: number } -// 1. _features OUTSIDE the component class (stable reference) -const _features = tableFeatures({}) // empty = core row model only +// 1. features OUTSIDE the component class (stable reference) +const features = tableFeatures({}) // empty = core row model only // 2. columns OUTSIDE the component class (stable reference) -const columns: Array> = [ +const columns: Array> = [ { accessorKey: 'firstName', header: 'First name', @@ -104,8 +104,8 @@ export class App { // 3. injectTable in an injection context (a class field qualifies) readonly table = injectTable(() => ({ - _features, // required in v9 - _rowModels: {}, // {} = core only; that's fine + features, // required in v9 + rowModels: {}, // {} = core only; that's fine columns, // stable ref data: this.data(), // signal read → re-syncs the table on change })) @@ -153,14 +153,14 @@ driven by the row model. ### What the boilerplate is doing - `tableFeatures({})` registers no opt-in features. The core row model - (`getRowModel()`) is always available. With `_features: tableFeatures({})`, + (`getRowModel()`) is always available. With `features: tableFeatures({})`, `table.atoms.*` only contains the slices core ships with — no `pagination`, no `sorting`, no `rowSelection` until you add the matching features. -- `_rowModels: {}` does not register any feature-specific row models. Core +- `rowModels: {}` does not register any feature-specific row models. Core row model is included automatically. - `injectTable(() => ({...}))` runs the initializer, builds the table, and re-runs the initializer whenever any signal read inside changes. Stable - references outside the initializer keep `columns` / `_features` / `_rowModels` + references outside the initializer keep `columns` / `features` / `rowModels` from getting recreated on every data update. --- @@ -169,9 +169,9 @@ driven by the row model. Each opt-in feature has two pieces in v9: -1. The **feature** itself (`rowSortingFeature`) in `_features` — adds APIs +1. The **feature** itself (`rowSortingFeature`) in `features` — adds APIs like `column.toggleSorting()` and the `sorting` state slice. -2. The **row-model factory** (`createSortedRowModel(sortFns)`) in `_rowModels` +2. The **row-model factory** (`createSortedRowModel(sortFns)`) in `rowModels` — produces the sorted output. Without it, `table.getRowModel().rows` is unsorted regardless of sort state. @@ -185,13 +185,13 @@ import { type ColumnDef, } from '@tanstack/angular-table' -const _features = tableFeatures({ +const features = tableFeatures({ rowSortingFeature, }) readonly table = injectTable(() => ({ - _features, - _rowModels: { + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns), // <-- enables sorting output }, columns, @@ -242,15 +242,15 @@ import { type ColumnDef, } from '@tanstack/angular-table' -const _features = tableFeatures({ +const features = tableFeatures({ rowSortingFeature, columnFilteringFeature, rowPaginationFeature, }) readonly table = injectTable(() => ({ - _features, - _rowModels: { + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns), filteredRowModel: createFilteredRowModel(filterFns), paginatedRowModel: createPaginatedRowModel(), @@ -301,7 +301,7 @@ for better inference across heterogeneous columns: ```ts import { createColumnHelper } from '@tanstack/angular-table' -const columnHelper = createColumnHelper() +const columnHelper = createColumnHelper() const columns = columnHelper.columns([ columnHelper.accessor('firstName', { @@ -320,10 +320,10 @@ const columns = columnHelper.columns([ ]) ``` -> v9 changed the generic order: `createColumnHelper()`, -> **not** `createColumnHelper()`. Same for `ColumnDef`. +> v9 changed the generic order: `createColumnHelper()`, +> **not** `createColumnHelper()`. Same for `ColumnDef`. -If multiple components share the same `_features` / `_rowModels`, factor them +If multiple components share the same `features` / `rowModels`, factor them into a `createTableHook(...)` call — see `tanstack-table/angular/angular-rendering-directives` §10 and the `composable-tables` example. @@ -337,8 +337,8 @@ row pinning, and refetch-based updates correct. ```ts readonly table = injectTable(() => ({ - _features, - _rowModels: { /* … */ }, + features, + rowModels: { /* … */ }, columns, data: this.data(), getRowId: (row) => row.id, // ← stable ID across re-fetches @@ -359,8 +359,8 @@ and `table.setSorting(...)` to drive updates. ```ts readonly table = injectTable(() => ({ - _features, - _rowModels: { /* … */ }, + features, + rowModels: { /* … */ }, columns, data: this.data(), initialState: { @@ -405,7 +405,7 @@ import { injectTable, tableFeatures } from '@tanstack/angular-table' There is no `getCoreRowModel()` / `getSortedRowModel()` / `getFilteredRowModel()` in v9. Core row model is automatic; the rest are `createSortedRowModel(sortFns)` / `createFilteredRowModel(filterFns)` / etc. -registered under `_rowModels`. +registered under `rowModels`. ### 3. (CRITICAL) Reimplementing what the table API already does @@ -425,36 +425,36 @@ The table already does all of this. Use it. ```ts // ❌ rowSortingFeature without createSortedRowModel → sort state changes, rows don't reorder -_features: tableFeatures({ rowSortingFeature }) -_rowModels: { +features: tableFeatures({ rowSortingFeature }) +rowModels: { } // ✅ -_rowModels: { +rowModels: { sortedRowModel: createSortedRowModel(sortFns) } ``` Full mapping table → [`references/feature-row-model-mapping.md`](references/feature-row-model-mapping.md). -### 5. (HIGH) Declaring `columns` / `_features` / `_rowModels` inside the initializer +### 5. (HIGH) Declaring `columns` / `features` / `rowModels` inside the initializer ```ts // ❌ Recreated on every signal change readonly table = injectTable(() => ({ - _features: tableFeatures({ rowSortingFeature }), - _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features: tableFeatures({ rowSortingFeature }), + rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns: [/* … */], data: this.data(), })) // ✅ Stable references outside, signal reads inside -const _features = tableFeatures({ rowSortingFeature }) -const columns: Array> = [/* … */] +const features = tableFeatures({ rowSortingFeature }) +const columns: Array> = [/* … */] readonly table = injectTable(() => ({ - _features, - _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, data: this.data(), })) diff --git a/packages/angular-table/skills/angular/getting-started/references/feature-row-model-mapping.md b/packages/angular-table/skills/angular/getting-started/references/feature-row-model-mapping.md index 0de278f2e3..6b80a67b5c 100644 --- a/packages/angular-table/skills/angular/getting-started/references/feature-row-model-mapping.md +++ b/packages/angular-table/skills/angular/getting-started/references/feature-row-model-mapping.md @@ -8,9 +8,9 @@ Reference material extracted from the getting-started SKILL.md. Every opt-in v9 feature has two pieces: -1. The **feature** itself in `_features` — adds APIs (e.g. +1. The **feature** itself in `features` — adds APIs (e.g. `column.toggleSorting()`) and the matching state slice. -2. A **row-model factory** in `_rowModels` — produces the derived row output. +2. A **row-model factory** in `rowModels` — produces the derived row output. Without it, sort/filter/paginate UI updates but rows don't reorder. | Feature | Row model needed | @@ -35,7 +35,7 @@ Every opt-in v9 feature has two pieces: const columnHelper = createColumnHelper() // ✅ v9 — features first -const columnHelper = createColumnHelper() +const columnHelper = createColumnHelper() ``` Or use `createAppColumnHelper()` from a `createTableHook(...)` factory, diff --git a/packages/angular-table/skills/angular/migrate-v8-to-v9/SKILL.md b/packages/angular-table/skills/angular/migrate-v8-to-v9/SKILL.md index 3760ae5cd6..ccb56f6f80 100644 --- a/packages/angular-table/skills/angular/migrate-v8-to-v9/SKILL.md +++ b/packages/angular-table/skills/angular/migrate-v8-to-v9/SKILL.md @@ -2,8 +2,8 @@ name: angular/migrate-v8-to-v9 description: > Mechanical v8 → v9 migration for `@tanstack/angular-table`: `createAngularTable` → - `injectTable`, `get*RowModel()` options → `_rowModels` factories with explicit `*Fns`, - required `_features` via `tableFeatures()`, state access via `table.atoms..get()` + `injectTable`, `get*RowModel()` options → `rowModels` factories with explicit `*Fns`, + required `features` via `tableFeatures()`, state access via `table.atoms..get()` or `table.state` instead of `table.getState()`, `createColumnHelper()` generic-order flip, every type now requires `TFeatures`, `enablePinning` split into `enableColumnPinning` / `enableRowPinning`, `sortingFn` → `sortFn` rename pile, `ColumnSizingInfo` → `ColumnResizing` @@ -27,8 +27,8 @@ sources: # Migrate from TanStack Table v8 to v9 (Angular) > **Angular does not ship a legacy v8 API in v9** (unlike React's -> `useLegacyTable`). You migrate directly to v9's `injectTable` + `_features` + -> `_rowModels` shape. There is no incremental in-place adapter — the public +> `useLegacyTable`). You migrate directly to v9's `injectTable` + `features` + +> `rowModels` shape. There is no incremental in-place adapter — the public > entrypoint name itself changes. This skill is a mechanical translation table. Work through it top-to-bottom. @@ -54,11 +54,11 @@ const v8Table = createAngularTable(() => ({ // v9 import { injectTable, tableFeatures } from '@tanstack/angular-table' -const _features = tableFeatures({}) // empty is valid; core row model is automatic +const features = tableFeatures({}) // empty is valid; core row model is automatic const v9Table = injectTable(() => ({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data: data(), })) @@ -66,12 +66,12 @@ const v9Table = injectTable(() => ({ Key behavioral change: **the `injectTable` initializer re-runs when signals inside it change**, then the adapter calls `table.setOptions({ ...prev, ...new })`. -Move stable values (`columns`, `_features`, `_rowModels`) **outside** the +Move stable values (`columns`, `features`, `rowModels`) **outside** the initializer so they aren't recreated on every data update. --- -## 2. Required new options: `_features` + `_rowModels` +## 2. Required new options: `features` + `rowModels` v9 is opt-in for every feature. **Both options are required.** @@ -102,15 +102,15 @@ import { sortFns, // note rename: sortingFns → sortFns } from '@tanstack/angular-table' -const _features = tableFeatures({ +const features = tableFeatures({ columnFilteringFeature, rowSortingFeature, rowPaginationFeature, }) injectTable(() => ({ - _features, - _rowModels: { + features, + rowModels: { filteredRowModel: createFilteredRowModel(filterFns), // fns are PARAMETERS now sortedRowModel: createSortedRowModel(sortFns), paginatedRowModel: createPaginatedRowModel(), @@ -166,8 +166,8 @@ readonly sorting = signal([]) readonly pagination = signal({ pageIndex: 0, pageSize: 10 }) readonly table = injectTable(() => ({ - _features, - _rowModels: { /* … */ }, + features, + rowModels: { /* … */ }, columns, data: this.data(), state: { @@ -200,7 +200,7 @@ readonly table = injectTable(() => ({ const columnHelper = createColumnHelper() // v9 — TFeatures FIRST, then TData -const columnHelper = createColumnHelper() +const columnHelper = createColumnHelper() ``` New in v9: `columnHelper.columns([...])` preserves each column's `TValue` — @@ -301,12 +301,12 @@ v8 backed reactivity with manual memoized getters. v9's adapter ## Migration checklist - [ ] Replace `createAngularTable` import + call with `injectTable`. -- [ ] Add `_features: tableFeatures({...})` (or `stockFeatures`) — required. -- [ ] Convert every `get*RowModel()` option to a `_rowModels.` entry with +- [ ] Add `features: tableFeatures({...})` (or `stockFeatures`) — required. +- [ ] Convert every `get*RowModel()` option to a `rowModels.` entry with the matching `create*RowModel(...)` factory. - [ ] Add `filterFns` / `sortFns` / `aggregationFns` as **factory parameters** where needed. -- [ ] Update `createColumnHelper()` → `createColumnHelper()`. +- [ ] Update `createColumnHelper()` → `createColumnHelper()`. - [ ] Update every `ColumnDef` / `Cell` etc. to include `TFeatures`. - [ ] Replace `table.getState().slice` reads with `table.atoms..get()` @@ -314,7 +314,7 @@ v8 backed reactivity with manual memoized getters. v9's adapter - [ ] Remove any usage of the v8 single `onStateChange` — split into per-slice `on[State]Change`. - [ ] In `on[State]Change` callbacks, handle both value and updater-fn shapes. -- [ ] Move `columns`, `_features`, `_rowModels` **outside** the `injectTable` +- [ ] Move `columns`, `features`, `rowModels` **outside** the `injectTable` initializer. - [ ] Switch any `flexRender` long-form to `*flexRenderCell` / `*flexRenderHeader` / `*flexRenderFooter` shorthand where applicable. @@ -326,7 +326,7 @@ v8 backed reactivity with manual memoized getters. v9's adapter - [ ] Rename `sortingFn` → `sortFn`, `getSortingFn` → `getSortFn`, `sortingFns` → `sortFns`, `SortingFn` → `SortFn`. - [ ] Replace `columnSizingInfo` state / setters / change handler with the - `columnResizing` equivalents; add `columnResizingFeature` to `_features` + `columnResizing` equivalents; add `columnResizingFeature` to `features` if you actually drag-resize. - [ ] Replace `enablePinning` with `enableColumnPinning` / `enableRowPinning`. - [ ] Update `ColumnMeta` module augmentation to include the `TFeatures` @@ -342,7 +342,7 @@ v8 backed reactivity with manual memoized getters. v9's adapter ### 1. (CRITICAL) Leaving `getCoreRowModel()` / `getSortedRowModel()` / etc. in v9 options -These options don't exist anymore. They become `_rowModels` entries with +These options don't exist anymore. They become `rowModels` entries with factory functions. The TypeScript error is loud but agents sometimes silence it with `as any` — don't. @@ -356,12 +356,12 @@ it must run from a class field, constructor, or ```ts // ❌ filtering enabled, but no filtered row model — UI changes, rows don't filter -_features: tableFeatures({ columnFilteringFeature }) -_rowModels: { +features: tableFeatures({ columnFilteringFeature }) +rowModels: { } // missing filteredRowModel // ✅ -_rowModels: { +rowModels: { filteredRowModel: createFilteredRowModel(filterFns) } ``` @@ -390,7 +390,7 @@ to default sort. const columnHelper = createColumnHelper() ``` -### 7. (HIGH) Putting `_features` / `columns` / row-model factories inside the `injectTable` initializer +### 7. (HIGH) Putting `features` / `columns` / row-model factories inside the `injectTable` initializer The v8 mental model was "build columns inside the hook". v9's `injectTable` initializer re-runs on every signal read change — keep heavy diff --git a/packages/angular-table/skills/angular/migrate-v8-to-v9/references/v8-to-v9-mapping.md b/packages/angular-table/skills/angular/migrate-v8-to-v9/references/v8-to-v9-mapping.md index 923f258664..b9f0ce2fe4 100644 --- a/packages/angular-table/skills/angular/migrate-v8-to-v9/references/v8-to-v9-mapping.md +++ b/packages/angular-table/skills/angular/migrate-v8-to-v9/references/v8-to-v9-mapping.md @@ -8,7 +8,7 @@ exhaustive lookup. ## Row-model migration table -| v8 option | v9 `_rowModels` key | v9 factory | +| v8 option | v9 `rowModels` key | v9 factory | | -------------------------- | --------------------- | --------------------------------------- | | `getCoreRowModel()` | (automatic) | — | | `getFilteredRowModel()` | `filteredRowModel` | `createFilteredRowModel(filterFns)` | @@ -44,7 +44,7 @@ exhaustive lookup. > > ```ts > import { stockFeatures } from '@tanstack/angular-table' -> _features: stockFeatures +> features: stockFeatures > ``` > > This restores v8-like "everything bundled" behavior — but the v9 bundle @@ -68,12 +68,12 @@ HeaderContext → HeaderContext CellContext → CellContext ``` -Easiest fix: extract `typeof _features` once. +Easiest fix: extract `typeof features` once. ```ts -const _features = tableFeatures({ rowSortingFeature, columnFilteringFeature }) +const features = tableFeatures({ rowSortingFeature, columnFilteringFeature }) -type Features = typeof _features +type Features = typeof features const columns: Array> = [ /* … */ @@ -171,13 +171,13 @@ during migration if you have shared base config: import { tableOptions, tableFeatures, rowSortingFeature } from '@tanstack/angular-table' const baseOptions = tableOptions({ - _features: tableFeatures({ rowSortingFeature }), + features: tableFeatures({ rowSortingFeature }), debugTable: isDevMode(), }) readonly table = injectTable(() => ({ ...baseOptions, - _rowModels: { /* … */ }, + rowModels: { /* … */ }, columns: this.columns, data: this.data(), })) @@ -213,7 +213,7 @@ and/or `enableRowPinning: true`. Replace state name `columnSizingInfo` with `columnResizing`, setter `setColumnSizingInfo` with `setColumnResizing`, handler `onColumnSizingInfoChange` with `onColumnResizingChange`. And add -`columnResizingFeature` to `_features` if you actually need resizing. +`columnResizingFeature` to `features` if you actually need resizing. ### Single global `onStateChange` ported as a giant per-slice fan-out @@ -224,13 +224,13 @@ actually care about — don't recreate a megaswitch. ### Hand-rolling `TFeatures` in render-fn types When a `cell` / `header` function signature requires `CellContext`, -let `createColumnHelper()` infer it for you. Spelling +let `createColumnHelper()` infer it for you. Spelling features by hand in dozens of render-fn signatures is a sign you should be using `createAppColumnHelper` from `createTableHook`. ### Reaching for `_`-prefixed internals because the public method "doesn't exist" -The "missing" method usually means the feature isn't in `_features`. Add the +The "missing" method usually means the feature isn't in `features`. Add the feature; don't peek at internals. ### Reimplementing what the table API already does diff --git a/packages/angular-table/skills/angular/production-readiness/SKILL.md b/packages/angular-table/skills/angular/production-readiness/SKILL.md index e4b63b69b9..29934f4a7b 100644 --- a/packages/angular-table/skills/angular/production-readiness/SKILL.md +++ b/packages/angular-table/skills/angular/production-readiness/SKILL.md @@ -1,8 +1,8 @@ --- name: angular/production-readiness description: > - Ship-ready optimizations for Angular Table v9: register only the `_features` you actually use - (tree-shake the bundle); keep `columns` / `_features` / `_rowModels` / feature-fn maps as + Ship-ready optimizations for Angular Table v9: register only the `features` you actually use + (tree-shake the bundle); keep `columns` / `features` / `rowModels` / feature-fn maps as stable references OUTSIDE the `injectTable` initializer; pass only the `*Fns` your data needs to `createSortedRowModel` / `createFilteredRowModel` / `createGroupedRowModel`; use `ChangeDetectionStrategy.OnPush`; lean on signal-backed atoms (`table.atoms..get()`) @@ -45,10 +45,10 @@ by the bundler. ```ts // ❌ Pulls in EVERY feature, even unused ones -const _features = stockFeatures +const features = stockFeatures // ✅ Only what this table actually uses -const _features = tableFeatures({ +const features = tableFeatures({ rowSortingFeature, rowPaginationFeature, columnFilteringFeature, @@ -70,13 +70,13 @@ import { } from '@tanstack/angular-table' // ❌ pulls in every built-in sort + filter fn -_rowModels: { +rowModels: { sortedRowModel: createSortedRowModel(sortFns), filteredRowModel: createFilteredRowModel(filterFns), } // ✅ only what you use -_rowModels: { +rowModels: { sortedRowModel: createSortedRowModel({ basic: sortFns.basic, datetime: sortFns.datetime }), filteredRowModel: createFilteredRowModel({ includesString: filterFns.includesString }), } @@ -94,27 +94,27 @@ Anything you create inside the initializer is recreated on every signal change. ```ts -// ❌ columns / _features / _rowModels / feature fns recreated on every data() change +// ❌ columns / features / rowModels / feature fns recreated on every data() change @Component({...}) export class App { readonly table = injectTable(() => ({ - _features: tableFeatures({ rowSortingFeature }), // ← new ref each run - _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, // ← new ref each run + features: tableFeatures({ rowSortingFeature }), // ← new ref each run + rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, // ← new ref each run columns: [/* … */], // ← new ref each run data: this.data(), })) } // ✅ stable references outside; only reactive reads inside -const _features = tableFeatures({ rowSortingFeature }) -const _rowModels = { sortedRowModel: createSortedRowModel(sortFns) } -const columns: Array> = [/* … */] +const features = tableFeatures({ rowSortingFeature }) +const rowModels = { sortedRowModel: createSortedRowModel(sortFns) } +const columns: Array> = [/* … */] @Component({...}) export class App { readonly table = injectTable(() => ({ - _features, - _rowModels, + features, + rowModels, columns, data: this.data(), })) @@ -125,7 +125,7 @@ Same rule for the controlled-state pattern — keep `state: { pagination: this.p inside the initializer, but keep the signal definitions on the class. For shared infrastructure across multiple tables, `createTableHook(...)` lets -you define `_features` / `_rowModels` / default options once at module scope. +you define `features` / `rowModels` / default options once at module scope. --- @@ -325,7 +325,7 @@ the wiring cost. Pick exactly one source of truth per slice (see ## 12. Build hygiene -- **`bundle-stats` / `source-map-explorer`**: after curating `_features`, +- **`bundle-stats` / `source-map-explorer`**: after curating `features`, verify your final bundle doesn't include retired features. If you see `rowGroupingFeature` in the bundle but never imported it, something is pulling in `stockFeatures` indirectly. @@ -336,11 +336,11 @@ the wiring cost. Pick exactly one source of truth per slice (see ## 13. Quick wins checklist -- [ ] `_features` listed explicitly (no `stockFeatures` in production). +- [ ] `features` listed explicitly (no `stockFeatures` in production). - [ ] `*Fns` registries passed only what you use to `createSortedRowModel` / `createFilteredRowModel` / `createGroupedRowModel`. -- [ ] `columns`, `_features`, `_rowModels`, feature fns are at module scope +- [ ] `columns`, `features`, `rowModels`, feature fns are at module scope or stable class fields — never inside the `injectTable` initializer. - [ ] Component is `ChangeDetectionStrategy.OnPush`. - [ ] `getRowId` set when rows have a stable primary key. @@ -366,7 +366,7 @@ the wiring cost. Pick exactly one source of truth per slice (see calls this out — `stockFeatures` is a v8 → v9 bootstrap, not a production end-state. -### 2. (CRITICAL) Recreating `columns` / `_features` / `_rowModels` inside the +### 2. (CRITICAL) Recreating `columns` / `features` / `rowModels` inside the `injectTable` initializer @@ -386,7 +386,7 @@ Symptoms: All of these are far slower than the built-in row models (which memoize and short-circuit) and ship more code. Use `table.setSorting(...)`, -`table.setColumnFilters(...)`, the registered `_rowModels` factories. +`table.setColumnFilters(...)`, the registered `rowModels` factories. ### 4. (HIGH) `OnPush` not set diff --git a/packages/angular-table/skills/angular/table-state/SKILL.md b/packages/angular-table/skills/angular/table-state/SKILL.md index 8d04f7576a..689c026a38 100644 --- a/packages/angular-table/skills/angular/table-state/SKILL.md +++ b/packages/angular-table/skills/angular/table-state/SKILL.md @@ -36,9 +36,9 @@ sources: --- -## 1. Prerequisites — `_features` and `_rowModels` decide what state exists +## 1. Prerequisites — `features` and `rowModels` decide what state exists -In v9, **a state slice only exists if its feature is registered in `_features`**. +In v9, **a state slice only exists if its feature is registered in `features`**. This is the #1 v9-specific gotcha and the root cause of many "missing API" TypeScript errors. @@ -54,14 +54,14 @@ import { } from '@tanstack/angular-table' // Declare features OUTSIDE the initializer (see §2 below) -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, rowSortingFeature, }) readonly table = injectTable(() => ({ - _features, - _rowModels: { + features, + rowModels: { paginatedRowModel: createPaginatedRowModel(), sortedRowModel: createSortedRowModel(sortFns), }, @@ -75,7 +75,7 @@ this.table.atoms.sorting.get() // ✅ ``` If you see `Property 'atoms.rowSelection' does not exist` or -`table.toggleRowSelected is not a function`, **add the feature to `_features`** — +`table.toggleRowSelected is not a function`, **add the feature to `features`** — don't reach for `@ts-ignore`, don't reimplement the API, don't switch to `stockFeatures` until you understand which features you actually need. @@ -90,8 +90,8 @@ run inside an Angular injection context (a component constructor / class field). ```ts readonly table = injectTable(() => ({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data: this.data(), })) @@ -105,25 +105,25 @@ That means: - **Reactive values that should re-sync the table** (`this.data()`, controlled state signals) go _inside_ the initializer. -- **Stable references** (`columns`, `_features`, `_rowModels`, feature-fn maps) +- **Stable references** (`columns`, `features`, `rowModels`, feature-fn maps) go _outside_ — or you'll recreate the column model on every data update. ```ts -// ❌ WRONG — columns + _features recreated on every data change +// ❌ WRONG — columns + features recreated on every data change readonly table = injectTable(() => ({ - _features: tableFeatures({ rowSortingFeature }), // new reference each run - _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, // ditto + features: tableFeatures({ rowSortingFeature }), // new reference each run + rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, // ditto columns: [/* … */], // ditto data: this.data(), })) // ✅ Stable references outside, signal reads inside -const _features = tableFeatures({ rowSortingFeature }) -const columns: Array> = [/* … */] +const features = tableFeatures({ rowSortingFeature }) +const columns: Array> = [/* … */] readonly table = injectTable(() => ({ - _features, - _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, data: this.data(), // ← only the signal read should be inside })) @@ -229,8 +229,8 @@ the value that reset APIs reset to. ```ts readonly table = injectTable(() => ({ - _features, - _rowModels: { /* … */ }, + features, + rowModels: { /* … */ }, columns, data: this.data(), initialState: { @@ -267,7 +267,7 @@ import { type SortingState, } from '@tanstack/angular-table' -const _features = tableFeatures({ rowPaginationFeature, rowSortingFeature }) +const features = tableFeatures({ rowPaginationFeature, rowSortingFeature }) export class Component { readonly data = signal>([]) @@ -275,8 +275,8 @@ export class Component { readonly pagination = signal({ pageIndex: 0, pageSize: 10 }) readonly table = injectTable(() => ({ - _features, - _rowModels: { + features, + rowModels: { /* … */ }, columns, @@ -333,9 +333,9 @@ right ownership model.** When you need more, see for slices owned by `@tanstack/store` / `@tanstack/angular-store`, when multiple non-table parts of the app share the slice. - **State type imports** — `PaginationState`, `SortingState`, - `RowSelectionState`, `TableState`, etc. + `RowSelectionState`, `TableState`, etc. - **`createTableHook(...)`** — app-wide `injectAppTable` / - `createAppColumnHelper` that pre-bind `_features` and `_rowModels`. Also + `createAppColumnHelper` that pre-bind `features` and `rowModels`. Also exposes `tableComponents` / `cellComponents` / `headerComponents` registries (covered in `angular-rendering-directives`). @@ -356,24 +356,24 @@ const table = createAngularTable(() => ({ // ✅ v9 import { injectTable, tableFeatures } from '@tanstack/angular-table' -const _features = tableFeatures({}) +const features = tableFeatures({}) const table = injectTable(() => ({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data: data(), })) ``` Also retired: `getFilteredRowModel`, `getSortedRowModel`, `getPaginationRowModel` -as top-level options → migrated to `_rowModels: { filteredRowModel: ..., sortedRowModel: ..., paginatedRowModel: ... }` +as top-level options → migrated to `rowModels: { filteredRowModel: ..., sortedRowModel: ..., paginatedRowModel: ... }` with explicit `*Fns` parameters. -### 2. (CRITICAL) Missing API because feature not in `_features` +### 2. (CRITICAL) Missing API because feature not in `features` `table.atoms.rowSelection`, `table.toggleAllRowsSelected`, `row.getCanSelect`, `column.getCanSort` etc. are **only** present when the -matching feature is in `_features`. The fix is to add the feature, not to +matching feature is in `features`. The fix is to add the feature, not to patch around it. ### 3. (CRITICAL) Reimplementing built-in state transitions @@ -394,7 +394,7 @@ Same for `setPageIndex`, `setPageSize`, `setSorting`, `toggleSorting`, ### 4. (HIGH) Expensive values declared **inside** the `injectTable` initializer Because the initializer re-runs when any reactive read inside it changes, -declaring `columns`, `_features`, `_rowModels`, or feature-fn maps inside the +declaring `columns`, `features`, `rowModels`, or feature-fn maps inside the function causes them to be recreated and re-applied on every data update. Move them outside the class or to stable class fields. diff --git a/packages/angular-table/skills/angular/table-state/references/external-atoms-and-app-hook.md b/packages/angular-table/skills/angular/table-state/references/external-atoms-and-app-hook.md index e02eac1d13..fb481b41ae 100644 --- a/packages/angular-table/skills/angular/table-state/references/external-atoms-and-app-hook.md +++ b/packages/angular-table/skills/angular/table-state/references/external-atoms-and-app-hook.md @@ -23,8 +23,8 @@ import { Store } from '@tanstack/store' const paginationAtom = new Store({ pageIndex: 0, pageSize: 10 }) readonly table = injectTable(() => ({ - _features, - _rowModels: { /* … */ }, + features, + rowModels: { /* … */ }, columns, data: this.data(), atoms: { @@ -60,15 +60,15 @@ import type { TableState, } from '@tanstack/angular-table' -// TableState is inferred from registered features -type MyTableState = TableState +// TableState is inferred from registered features +type MyTableState = TableState ``` --- ## `createTableHook` — app-wide table infrastructure -When multiple tables in an app share the same `_features`, `_rowModels`, and +When multiple tables in an app share the same `features`, `rowModels`, and component conventions, factor them into a `createTableHook(...)` call once and import the resulting `injectAppTable` / `createAppColumnHelper`. @@ -91,8 +91,8 @@ export const { injectTableCellContext, injectTableHeaderContext, } = createTableHook({ - _features: tableFeatures({ rowSortingFeature, rowPaginationFeature }), - _rowModels: { + features: tableFeatures({ rowSortingFeature, rowPaginationFeature }), + rowModels: { sortedRowModel: createSortedRowModel(sortFns), paginatedRowModel: createPaginatedRowModel(), }, @@ -110,7 +110,7 @@ const columnHelper = createAppColumnHelper() // only TData generic neede readonly table = injectAppTable(() => ({ columns, data: this.data(), -})) // _features & _rowModels inherited +})) // features & rowModels inherited ``` `createTableHook` also lets you register `tableComponents` / `cellComponents` / diff --git a/packages/angular-table/src/helpers/createTableHook.ts b/packages/angular-table/src/helpers/createTableHook.ts index ffd043be64..4253246332 100644 --- a/packages/angular-table/src/helpers/createTableHook.ts +++ b/packages/angular-table/src/helpers/createTableHook.ts @@ -335,7 +335,7 @@ export type CreateTableHookResult< injectAppTable: ( tableOptions: () => Omit< TableOptions, - '_features' | '_rowModels' + 'features' | 'rowModels' >, ) => AppAngularTable< TFeatures, @@ -357,8 +357,8 @@ export type CreateTableHookResult< * @example * ```ts * const { injectAppTable, createAppColumnHelper } = createTableHook({ - * _features, - * _rowModels: {}, + * features, + * rowModels: {}, * tableComponents: {}, * cellComponents: {}, * headerComponents: {}, @@ -426,7 +426,7 @@ export function createTableHook< >( tableOptions: () => Omit< TableOptions, - '_features' | '_rowModels' + 'features' | 'rowModels' >, ): AppAngularTable< TFeatures, @@ -463,8 +463,8 @@ export function createTableHook< return { ...defaultTableOptions, ...tableOptions(), - _features: { - ...defaultTableOptions._features, + features: { + ...defaultTableOptions.features, appTableFeatures, }, } as TableOptions diff --git a/packages/angular-table/src/injectTable.ts b/packages/angular-table/src/injectTable.ts index 4f59232b03..7803f2be20 100644 --- a/packages/angular-table/src/injectTable.ts +++ b/packages/angular-table/src/injectTable.ts @@ -115,14 +115,14 @@ function createStateProxy< * ```ts * // Register only the features you need * import {tableFeatures, rowPaginationFeature} from '@tanstack/angular-table'; - * const _features = tableFeatures({ + * const features = tableFeatures({ * rowPaginationFeature, * // ...all other features you need * }) * * // Use all table core features * import {stockFeatures} from '@tanstack/angular-table'; - * const _features = tableFeatures(stockFeatures); + * const features = tableFeatures(stockFeatures); * ``` * 2. Prepare the table columns * ```ts @@ -130,13 +130,13 @@ function createStateProxy< * * type MyData = {} * - * const columns: ColumnDef[] = [ + * const columns: ColumnDef[] = [ * // ...column definitions * ] * * // or using createColumnHelper * import {createColumnHelper} from '@tanstack/angular-table'; - * const columnHelper = createColumnHelper(); + * const columnHelper = createColumnHelper(); * const columns = columnHelper.columns([ * columnHelper.accessor(...), * // ...other columns @@ -146,7 +146,7 @@ function createStateProxy< * ```ts * const table = injectTable(() => { * // ...table options, - * _features, + * features, * columns: columns, * data: myDataSignal(), * }) @@ -168,9 +168,9 @@ export function injectTable< lazyInit(() => { const table = constructTable({ ...options(), - _features: { + features: { coreReativityFeature: angularReactivity(injector), - ...options()._features, + ...options().features, }, }) as AngularTable diff --git a/packages/angular-table/tests/angularReactivityFeature.test.ts b/packages/angular-table/tests/angularReactivityFeature.test.ts index d0bd32fe10..e1a3b1851d 100644 --- a/packages/angular-table/tests/angularReactivityFeature.test.ts +++ b/packages/angular-table/tests/angularReactivityFeature.test.ts @@ -28,7 +28,7 @@ describe('angularReactivityFeature', () => { return TestBed.runInInjectionContext(() => injectTable(() => ({ data: _data(), - _features: { ...stockFeatures }, + features: { ...stockFeatures }, columns: columns, getRowId: (row) => row.id, })), @@ -109,7 +109,7 @@ describe('angularReactivityFeature', () => { const table = TestBed.runInInjectionContext(() => injectTable(() => ({ data: data(), - _features: { ...stockFeatures }, + features: { ...stockFeatures }, columns: columns, getRowId: (row) => row.id, atoms: { @@ -164,7 +164,7 @@ describe('angularReactivityFeature', () => { const table = TestBed.runInInjectionContext(() => injectTable(() => ({ data: data(), - _features: { ...stockFeatures }, + features: { ...stockFeatures }, columns: columns, getRowId: (row) => row.id, state: { @@ -200,7 +200,7 @@ describe('angularReactivityFeature', () => { const table = TestBed.runInInjectionContext(() => injectTable(() => ({ data: data(), - _features: { ...stockFeatures }, + features: { ...stockFeatures }, columns: columns, getRowId: (row) => row.id, initialState: { @@ -220,7 +220,7 @@ describe('angularReactivityFeature', () => { const table = TestBed.runInInjectionContext(() => injectTable(() => ({ data: data(), - _features: { ...stockFeatures }, + features: { ...stockFeatures }, columns: columns, getRowId: (row) => row.id, initialState: { @@ -259,7 +259,7 @@ describe('angularReactivityFeature', () => { const table = TestBed.runInInjectionContext(() => injectTable(() => ({ data: data(), - _features: { ...stockFeatures }, + features: { ...stockFeatures }, columns: columns, getRowId: (row) => row.id, initialState: { @@ -295,8 +295,8 @@ describe('angularReactivityFeature', () => { const table = TestBed.runInInjectionContext(() => injectTable(() => ({ data: data(), - _features: stockFeatures, - _rowModels: {}, + features: stockFeatures, + rowModels: {}, columns: columns, getRowId: (row) => row.id, initialState: { diff --git a/packages/angular-table/tests/flex-render/flex-render-table.test.ts b/packages/angular-table/tests/flex-render/flex-render-table.test.ts index c3111e43f9..ccee3f189c 100644 --- a/packages/angular-table/tests/flex-render/flex-render-table.test.ts +++ b/packages/angular-table/tests/flex-render/flex-render-table.test.ts @@ -307,8 +307,8 @@ describe('FlexRenderDirective', () => { return { columns: columns, data: defaultData, - _features: stockFeatures, - _rowModels: { + features: stockFeatures, + rowModels: { coreRowModel: createCoreRowModel(), }, state: { expanded: this.expandState() }, @@ -408,8 +408,8 @@ describe('FlexRenderDirective', () => { return { columns: columns, data: defaultData, - _features: stockFeatures, - _rowModels: { + features: stockFeatures, + rowModels: { coreRowModel: createCoreRowModel(), }, state: { expanded: this.expandState() }, @@ -534,7 +534,7 @@ export function createTestTable( readonly table = injectTable(() => { return { ...(optionsFn?.() ?? {}), - _features: stockFeatures, + features: stockFeatures, columns: this.columns(), data: this.data(), } as TableOptions diff --git a/packages/angular-table/tests/injectTable.test.ts b/packages/angular-table/tests/injectTable.test.ts index 8de7e0b51f..2f3fef0bed 100644 --- a/packages/angular-table/tests/injectTable.test.ts +++ b/packages/angular-table/tests/injectTable.test.ts @@ -29,7 +29,7 @@ describe('injectTable', () => { table = injectTable(() => ({ data: this.data(), - _features: stockFeatures, + features: stockFeatures, columns: [], })) } @@ -58,7 +58,7 @@ describe('injectTable', () => { const table = TestBed.runInInjectionContext(() => injectTable(() => ({ data: data(), - _features: stockFeatures, + features: stockFeatures, columns: columns, getRowId: (row) => row.id, })), @@ -97,8 +97,8 @@ describe('injectTable', () => { const table = injectTable(() => ({ data, columns: columns, - _features: stockFeatures, - _rowModels: { + features: stockFeatures, + rowModels: { paginatedRowModel: createPaginatedRowModel(), }, getRowId: (row) => row.id, diff --git a/packages/lit-table/skills/lit/compose-with-tanstack-virtual/SKILL.md b/packages/lit-table/skills/lit/compose-with-tanstack-virtual/SKILL.md index e000576fc5..925607ee04 100644 --- a/packages/lit-table/skills/lit/compose-with-tanstack-virtual/SKILL.md +++ b/packages/lit-table/skills/lit/compose-with-tanstack-virtual/SKILL.md @@ -59,9 +59,9 @@ import { type ColumnDef, } from '@tanstack/lit-table' -const _features = tableFeatures({ columnSizingFeature, rowSortingFeature }) +const features = tableFeatures({ columnSizingFeature, rowSortingFeature }) -const columns: Array> = [ +const columns: Array> = [ { accessorKey: 'id', header: 'ID', size: 60 }, { accessorKey: 'firstName', @@ -76,7 +76,7 @@ class VirtualizedTable extends LitElement { @state() private _data: Person[] = makeData(50_000) - private tableController = new TableController(this) + private tableController = new TableController(this) private rowVirtualizerController!: VirtualizerController private tableContainerRef: Ref = createRef() @@ -93,8 +93,8 @@ class VirtualizedTable extends LitElement { protected render() { const table = this.tableController.table( { - _features, - _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, data: this._data, }, diff --git a/packages/lit-table/skills/lit/getting-started/SKILL.md b/packages/lit-table/skills/lit/getting-started/SKILL.md index 3cc29735d2..3eaae41768 100644 --- a/packages/lit-table/skills/lit/getting-started/SKILL.md +++ b/packages/lit-table/skills/lit/getting-started/SKILL.md @@ -2,8 +2,8 @@ name: lit/getting-started description: > End-to-end first-table journey for `@tanstack/lit-table` v9: install the - adapter (plus required `lit` and `@lit/context` peers), declare `_features` - via `tableFeatures()`, declare `_rowModels` with their factories, build a + adapter (plus required `lit` and `@lit/context` peers), declare `features` + via `tableFeatures()`, declare `rowModels` with their factories, build a typed column helper, construct one `TableController` per LitElement host, call `.table(options, selector?)` inside `render()`, and render with `FlexRender({ cell|header|footer })`. Routing keywords: install lit-table, @@ -41,7 +41,7 @@ Peer dependency versions: `lit ^3.1.3`, `@lit/context ^1.1.0`. Source: `packages/lit-table/package.json`. -## Step 1 — Declare `_features` +## Step 1 — Declare `features` v9 is explicit about what a table uses. Use `tableFeatures({...})` at module scope. The TypeScript shape drives state inference, API surface, and tree-shaking. @@ -52,19 +52,19 @@ import { rowSortingFeature, } from '@tanstack/lit-table' -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, rowSortingFeature, }) ``` -If `_features` does not include `rowSelectionFeature`, then `table.atoms.rowSelection`, `table.setRowSelection`, etc. become TypeScript errors — and the runtime won't ship that logic. Pass `tableFeatures({})` for a minimum-overhead table with just the core row model. +If `features` does not include `rowSelectionFeature`, then `table.atoms.rowSelection`, `table.setRowSelection`, etc. become TypeScript errors — and the runtime won't ship that logic. Pass `tableFeatures({})` for a minimum-overhead table with just the core row model. Source: `docs/framework/lit/lit-table.md`; `docs/guide/features.md`. -## Step 2 — Declare `_rowModels` +## Step 2 — Declare `rowModels` -Each registered feature that needs a row-model stage maps to a factory under `_rowModels`. The factory takes a record of \*Fns for that stage. +Each registered feature that needs a row-model stage maps to a factory under `rowModels`. The factory takes a record of \*Fns for that stage. ```ts import { @@ -73,13 +73,13 @@ import { sortFns, } from '@tanstack/lit-table' -const _rowModels = { +const rowModels = { paginatedRowModel: createPaginatedRowModel(), sortedRowModel: createSortedRowModel(sortFns), } ``` -The core row model is always included — `_rowModels: {}` is valid for a feature-free table. +The core row model is always included — `rowModels: {}` is valid for a feature-free table. ## Step 3 — Type your data and build columns @@ -96,7 +96,7 @@ type Person = { progress: number } -const columns: Array> = [ +const columns: Array> = [ { accessorKey: 'firstName', header: 'First Name', @@ -119,7 +119,7 @@ const columns: Array> = [ ] ``` -For a more type-safe path, use `createColumnHelper()`. +For a more type-safe path, use `createColumnHelper()`. Source: `examples/lit/basic-table-controller/src/main.ts`. @@ -135,7 +135,7 @@ import { FlexRender, TableController } from '@tanstack/lit-table' class LitTableExample extends LitElement { // ONE controller per host. Constructed as a class field so the constructor's // `host.addController(this)` call happens once. - private tableController = new TableController(this) + private tableController = new TableController(this) @state() private data: Person[] = makeData(20) @@ -150,8 +150,8 @@ class LitTableExample extends LitElement { // Later calls merge options into the same instance. const table = this.tableController.table( { - _features, - _rowModels, + features, + rowModels, columns, data: this.data, }, @@ -239,7 +239,7 @@ Wrong: ```ts protected render() { - const controller = new TableController(this) // every frame + const controller = new TableController(this) // every frame const table = controller.table({ /* … */ }) } ``` @@ -247,21 +247,21 @@ protected render() { Correct: ```ts -private tableController = new TableController(this) // once per host +private tableController = new TableController(this) // once per host ``` A new controller per render registers a new subscription and resets table state every frame. Source: `packages/lit-table/src/TableController.ts`. -### CRITICAL Calling a feature API when the feature is not in `_features` +### CRITICAL Calling a feature API when the feature is not in `features` Wrong: ```ts -const _features = tableFeatures({}) // no rowPaginationFeature +const features = tableFeatures({}) // no rowPaginationFeature const table = this.tableController.table({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data: this.data, }) @@ -271,10 +271,10 @@ table.setPageIndex(0) // TypeScript error AND runtime no-op Correct: ```ts -const _features = tableFeatures({ rowPaginationFeature }) +const features = tableFeatures({ rowPaginationFeature }) const table = this.tableController.table({ - _features, - _rowModels: { paginatedRowModel: createPaginatedRowModel() }, + features, + rowModels: { paginatedRowModel: createPaginatedRowModel() }, columns, data: this.data, }) @@ -288,8 +288,8 @@ Source: `docs/guide/features.md`. Wrong: ```ts -const _features = tableFeatures({ rowSortingFeature }) -const table = this.tableController.table({ _features, _rowModels: {} /* … */ }) +const features = tableFeatures({ rowSortingFeature }) +const table = this.tableController.table({ features, rowModels: {} /* … */ }) table.setSorting([{ id: 'age', desc: true }]) // rows are NOT sorted — no sortedRowModel registered ``` @@ -297,19 +297,19 @@ table.setSorting([{ id: 'age', desc: true }]) Correct: ```ts -const _features = tableFeatures({ rowSortingFeature }) +const features = tableFeatures({ rowSortingFeature }) const table = this.tableController.table({ - _features, - _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, /* … */ }) ``` -### HIGH Building `_features` / `columns` / `data` inside `render()` +### HIGH Building `features` / `columns` / `data` inside `render()` Wrong: re-creating these every frame busts internal memos. -Correct: `_features` and `columns` at module scope; `data` from a `@state()` field on the element. +Correct: `features` and `columns` at module scope; `data` from a `@state()` field on the element. Source: `docs/framework/lit/guide/table-state.md` (FAQ #1). ### HIGH Reimplementing built-in feature logic diff --git a/packages/lit-table/skills/lit/lit-table-controller/SKILL.md b/packages/lit-table/skills/lit/lit-table-controller/SKILL.md index 9062252303..697181fa89 100644 --- a/packages/lit-table/skills/lit/lit-table-controller/SKILL.md +++ b/packages/lit-table/skills/lit/lit-table-controller/SKILL.md @@ -39,9 +39,9 @@ export class TableController implements ReactiveController { // First call: build the core table with the Lit reactivity bindings. this._table = constructTable({ ...tableOptions, - _features: { + features: { coreReativityFeature: litReactivity(), - ...tableOptions._features, + ...tableOptions.features, }, mergeOptions: (def, next) => ({ ...def, ...next }), }) @@ -112,16 +112,16 @@ import { type ColumnDef, } from '@tanstack/lit-table' -const _features = tableFeatures({}) // module scope +const features = tableFeatures({}) // module scope -const columns: Array> = [ +const columns: Array> = [ /* … module scope … */ ] @customElement('people-table') class PeopleTable extends LitElement { // ONE controller, constructed as a class field. - private tableController = new TableController(this) + private tableController = new TableController(this) @state() private data: Person[] = [] @@ -129,8 +129,8 @@ class PeopleTable extends LitElement { protected render() { const table = this.tableController.table( { - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data: this.data, }, @@ -227,7 +227,7 @@ Wrong: ```ts protected render() { - const controller = new TableController(this) // every frame + const controller = new TableController(this) // every frame const table = controller.table({ /* … */ }) } ``` @@ -235,7 +235,7 @@ protected render() { Correct: construct the controller once as a class field. ```ts -private tableController = new TableController(this) +private tableController = new TableController(this) protected render() { const table = this.tableController.table({ /* … */ }) @@ -252,7 +252,7 @@ Wrong: ```ts connectedCallback() { super.connectedCallback() - this.cachedTable = this.tableController.table({ _features, _rowModels: {}, columns, data: this.data }) + this.cachedTable = this.tableController.table({ features, rowModels: {}, columns, data: this.data }) } protected render() { @@ -264,7 +264,7 @@ Correct: call `.table()` each `render()`. The options are merged into the same l ```ts protected render() { - const table = this.tableController.table({ _features, _rowModels: {}, columns, data: this.data }) + const table = this.tableController.table({ features, rowModels: {}, columns, data: this.data }) return html`${table.getRowModel().rows.map(/* … */)}` } ``` @@ -278,21 +278,21 @@ Wrong: assuming `table.Subscribe({ source: table.atoms.rowSelection, … })` mak Correct: in the current adapter, the host's `requestUpdate()` is wired to the full `table.store` and `table.optionsStore`. `Subscribe` is a render-time projection convenience; it does not narrow host invalidation. Plan accordingly for large lists. Source: `packages/lit-table/src/TableController.ts` (lines 200–218 + `_setupSubscriptions`). -### HIGH Building `_features` inside `render()` +### HIGH Building `features` inside `render()` Wrong: ```ts protected render() { - const _features = tableFeatures({ rowSortingFeature }) // new each frame - const table = this.tableController.table({ _features, /* … */ }) + const features = tableFeatures({ rowSortingFeature }) // new each frame + const table = this.tableController.table({ features, /* … */ }) } ``` -Correct: declare `_features` at module scope (or once on the class, frozen). Identity drives internal memos. +Correct: declare `features` at module scope (or once on the class, frozen). Identity drives internal memos. ```ts -const _features = tableFeatures({ rowSortingFeature }) +const features = tableFeatures({ rowSortingFeature }) ``` Source: `docs/framework/lit/guide/table-state.md` (FAQ #1). diff --git a/packages/lit-table/skills/lit/migrate-v8-to-v9/SKILL.md b/packages/lit-table/skills/lit/migrate-v8-to-v9/SKILL.md index 182d2086af..b5e1f0e9c8 100644 --- a/packages/lit-table/skills/lit/migrate-v8-to-v9/SKILL.md +++ b/packages/lit-table/skills/lit/migrate-v8-to-v9/SKILL.md @@ -4,10 +4,10 @@ description: > Mechanical breaking-change migration from TanStack Table v8 to v9 for `@tanstack/lit-table`. v8's `TableController(host, () => options)` shape collapses to v9's `new TableController(host)` + `.table(options, selector?)`; - per-row-model `get*RowModel` options become `_features` + `_rowModels`; + per-row-model `get*RowModel` options become `features` + `rowModels`; `flexRender(def, ctx)` becomes `FlexRender({ cell|header|footer })`; core types gain a `TFeatures` first generic. Routing keywords: lit v8 to v9, - migration, TableController v8, get*RowModel, _features lit. + migration, TableController v8, get*RowModel, features lit. type: lifecycle library: tanstack-table framework: lit @@ -25,22 +25,22 @@ sources: > **Maintainer note:** the Lit adapter is scheduled for a rewrite alongside TanStack Lit Store during the v9 beta cycle. APIs in this skill may change in a future beta. The patterns below match `9.0.0-alpha.48`. -The Lit v9 adapter mirrors v9's React surface (atoms, `_features`, `_rowModels`, FlexRender) wrapped in a `ReactiveController`. There is no `useLegacyTable` shim — migrate directly. +The Lit v9 adapter mirrors v9's React surface (atoms, `features`, `rowModels`, FlexRender) wrapped in a `ReactiveController`. There is no `useLegacyTable` shim — migrate directly. ## The Core Mapping -| v8 (`@tanstack/lit-table`) | v9 (`@tanstack/lit-table`) | -| ---------------------------------------------------- | ---------------------------------------------------------------------------------------------------- | -| `new TableController(host, () => options)` | `new TableController(host)` then `.table(options, selector?)` | -| `controller.table` (property) | `controller.table(opts, selector?)` (method, called each `render()`) | -| `getCoreRowModel: getCoreRowModel()` option | core row model included by default — `_rowModels: {}` valid | -| `getSortedRowModel: getSortedRowModel()` | `_features: { rowSortingFeature }` + `_rowModels: { sortedRowModel: createSortedRowModel(sortFns) }` | -| `getFilteredRowModel`, `getPaginationRowModel`, etc. | matching `*Feature` + matching `_rowModels` factory | -| `flexRender(def, ctx)` | `FlexRender({ cell })` / `FlexRender({ header })` / `FlexRender({ footer })` | -| `state` + `on*Change` only | still supported; new `atoms` per-slice option preferred | -| `createColumnHelper()` | `createColumnHelper()` | -| `ColumnDef` | `ColumnDef` | -| `Table` | `Table` | +| v8 (`@tanstack/lit-table`) | v9 (`@tanstack/lit-table`) | +| ---------------------------------------------------- | -------------------------------------------------------------------------------------------------- | +| `new TableController(host, () => options)` | `new TableController(host)` then `.table(options, selector?)` | +| `controller.table` (property) | `controller.table(opts, selector?)` (method, called each `render()`) | +| `getCoreRowModel: getCoreRowModel()` option | core row model included by default — `rowModels: {}` valid | +| `getSortedRowModel: getSortedRowModel()` | `features: { rowSortingFeature }` + `rowModels: { sortedRowModel: createSortedRowModel(sortFns) }` | +| `getFilteredRowModel`, `getPaginationRowModel`, etc. | matching `*Feature` + matching `rowModels` factory | +| `flexRender(def, ctx)` | `FlexRender({ cell })` / `FlexRender({ header })` / `FlexRender({ footer })` | +| `state` + `on*Change` only | still supported; new `atoms` per-slice option preferred | +| `createColumnHelper()` | `createColumnHelper()` | +| `ColumnDef` | `ColumnDef` | +| `Table` | `Table` | Source: `docs/framework/lit/lit-table.md`; `packages/lit-table/src/TableController.ts`. @@ -65,13 +65,13 @@ protected render() { ```ts // v9 — controller takes only the host. Options pass to .table(...) inside render. -private tableController = new TableController(this) +private tableController = new TableController(this) protected render() { const table = this.tableController.table( { - _features, - _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, data: this.data, }, @@ -82,7 +82,7 @@ protected render() { } ``` -### 2. Replace `get*RowModel` options with `_features` + `_rowModels` +### 2. Replace `get*RowModel` options with `features` + `rowModels` ```ts // v8 @@ -95,15 +95,15 @@ protected render() { } // v9 -const _features = tableFeatures({ +const features = tableFeatures({ rowSortingFeature, columnFilteringFeature, rowPaginationFeature, }) { - _features, - _rowModels: { + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns), filteredRowModel: createFilteredRowModel(filterFns), paginatedRowModel: createPaginatedRowModel(), @@ -112,7 +112,7 @@ const _features = tableFeatures({ } ``` -Move `_features` to module scope. Reference identity matters. +Move `features` to module scope. Reference identity matters. Source: `docs/framework/lit/lit-table.md`. ### 3. Update column types and helpers @@ -125,11 +125,12 @@ const columns: ColumnDef[] = columnHelper.columns([ ]) // v9 -const columnHelper = createColumnHelper() -const columns: Array> = - columnHelper.columns([ +const columnHelper = createColumnHelper() +const columns: Array> = columnHelper.columns( + [ /* … */ - ]) + ], +) ``` `TFeatures` is now the first generic on `ColumnDef`, `Table`, and `createColumnHelper`. @@ -209,8 +210,8 @@ Wrong: ```ts this.tableController.table({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, getSortedRowModel: getSortedRowModel(), // ignored @@ -220,26 +221,26 @@ this.tableController.table({ Correct: ```ts -const _features = tableFeatures({ rowSortingFeature }) +const features = tableFeatures({ rowSortingFeature }) this.tableController.table({ - _features, - _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, data, }) ``` -v9 doesn't read `get*RowModel` options. Features need both registration in `_features` and a factory in `_rowModels`. +v9 doesn't read `get*RowModel` options. Features need both registration in `features` and a factory in `rowModels`. ### CRITICAL Calling a feature API without registering the feature Wrong: ```ts -const _features = tableFeatures({}) // no rowSelectionFeature +const features = tableFeatures({}) // no rowSelectionFeature const table = this.tableController.table({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, }) @@ -249,10 +250,10 @@ table.getIsAllRowsSelected() // type error / runtime no-op Correct: ```ts -const _features = tableFeatures({ rowSelectionFeature }) +const features = tableFeatures({ rowSelectionFeature }) const table = this.tableController.table({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, enableRowSelection: true, @@ -266,7 +267,7 @@ Source: `docs/guide/features.md`. Wrong: still passing `getCoreRowModel` — v9 includes the core row model automatically. -Correct: drop it. `_rowModels: {}` is valid. +Correct: drop it. `rowModels: {}` is valid. ### HIGH Single-generic column helper / `ColumnDef` @@ -282,8 +283,8 @@ const columns: ColumnDef[] = [ Correct: ```ts -const columnHelper = createColumnHelper() -const columns: Array> = [ +const columnHelper = createColumnHelper() +const columns: Array> = [ /* … */ ] ``` diff --git a/packages/lit-table/skills/lit/table-state/SKILL.md b/packages/lit-table/skills/lit/table-state/SKILL.md index cb7f17489e..c1f46502d6 100644 --- a/packages/lit-table/skills/lit/table-state/SKILL.md +++ b/packages/lit-table/skills/lit/table-state/SKILL.md @@ -36,7 +36,7 @@ This skill builds on `tanstack-table/state-management` and `tanstack-table/setup ## Setup -The shape every Lit v9 table follows: register `_features` and `_rowModels` at module scope, construct `TableController` once per host element, and call `.table(options, selector?)` from inside `render()`. +The shape every Lit v9 table follows: register `features` and `rowModels` at module scope, construct `TableController` once per host element, and call `.table(options, selector?)` from inside `render()`. ```ts import { LitElement, html } from 'lit' @@ -54,9 +54,9 @@ import { type Person = { firstName: string; lastName: string; age: number } -const _features = tableFeatures({ rowSortingFeature }) +const features = tableFeatures({ rowSortingFeature }) -const columns: Array> = [ +const columns: Array> = [ { accessorKey: 'firstName', header: 'First Name', @@ -69,7 +69,7 @@ const columns: Array> = [ @customElement('people-table') export class PeopleTable extends LitElement { // ONE controller per host. The constructor calls host.addController(this). - private tableController = new TableController(this) + private tableController = new TableController(this) @state() private data: Person[] = [] @@ -77,8 +77,8 @@ export class PeopleTable extends LitElement { protected render() { const table = this.tableController.table( { - _features, - _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, data: this.data, }, @@ -145,7 +145,7 @@ The selector is a function from full table state to whatever you want exposed on ```ts const table = this.tableController.table( - { _features, _rowModels: {}, columns, data: this._data }, + { features, rowModels: {}, columns, data: this._data }, (state) => ({ pagination: state.pagination }), ) @@ -198,7 +198,7 @@ import { type PaginationState, } from '@tanstack/lit-table' -const _features = tableFeatures({ rowPaginationFeature }) +const features = tableFeatures({ rowPaginationFeature }) // Module-scope atoms — stable identity, shareable across components. const paginationAtom = createAtom({ @@ -208,12 +208,12 @@ const paginationAtom = createAtom({ @customElement('my-table') class MyTable extends LitElement { - private tableController = new TableController(this) + private tableController = new TableController(this) protected render() { const table = this.tableController.table({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data: this._data, atoms: { pagination: paginationAtom }, @@ -237,8 +237,8 @@ private _sorting: SortingState = [] protected render() { const table = this.tableController.table({ - _features, - _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, data: this._data, state: { sorting: this._sorting }, @@ -253,12 +253,12 @@ Source: `docs/framework/lit/guide/table-state.md`. ### 7. `createTableHook` for reusable shared config -Bundle `_features`, `_rowModels`, default options, and pre-bound cell/header components. You get `useAppTable(host, options, selector?)`, `createAppColumnHelper`, and `useTableContext` / `useCellContext` / `useHeaderContext` (Lit Context consumers). +Bundle `features`, `rowModels`, default options, and pre-bound cell/header components. You get `useAppTable(host, options, selector?)`, `createAppColumnHelper`, and `useTableContext` / `useCellContext` / `useHeaderContext` (Lit Context consumers). ```ts const { useAppTable, createAppColumnHelper } = createTableHook({ - _features: tableFeatures({ rowSortingFeature }), - _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features: tableFeatures({ rowSortingFeature }), + rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, }) const columnHelper = createAppColumnHelper() @@ -319,7 +319,7 @@ Wrong: ```ts protected render() { - const controller = new TableController(this) // new instance every render + const controller = new TableController(this) // new instance every render const table = controller.table({ /* … */ }) } ``` @@ -328,7 +328,7 @@ Correct: ```ts class MyTable extends LitElement { - private tableController = new TableController(this) // once + private tableController = new TableController(this) // once protected render() { const table = this.tableController.table({ @@ -341,15 +341,15 @@ class MyTable extends LitElement { Each `new TableController(host)` registers another controller on the host. The original table is discarded; the new one resubscribes; state is reset every render. Source: `packages/lit-table/src/TableController.ts`. -### CRITICAL Calling a feature API when the feature is not in `_features` +### CRITICAL Calling a feature API when the feature is not in `features` Wrong: ```ts -const _features = tableFeatures({}) // no rowPaginationFeature +const features = tableFeatures({}) // no rowPaginationFeature const table = this.tableController.table({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data: this._data, }) @@ -359,10 +359,10 @@ table.setPageIndex(0) // TypeScript error AND runtime no-op Correct: ```ts -const _features = tableFeatures({ rowPaginationFeature }) +const features = tableFeatures({ rowPaginationFeature }) const table = this.tableController.table({ - _features, - _rowModels: { paginatedRowModel: createPaginatedRowModel() }, + features, + rowModels: { paginatedRowModel: createPaginatedRowModel() }, columns, data: this._data, }) @@ -400,9 +400,9 @@ private appTable = (() => { Source: `examples/lit/basic-app-table/src/main.ts` (lines 77–90). -### HIGH Unstable `_features` / `columns` / `data` references +### HIGH Unstable `features` / `columns` / `data` references -Wrong: building `_features` or `columns` inside `render()` so a new array/object is allocated every frame. +Wrong: building `features` or `columns` inside `render()` so a new array/object is allocated every frame. Correct: declare at module scope. For `data`, prefer a `@state()` field; for derived data, memoize where the dependency actually changes. Source: `docs/framework/lit/guide/table-state.md` (FAQ #1). @@ -411,7 +411,7 @@ Source: `docs/framework/lit/guide/table-state.md` (FAQ #1). Wrong: hand-rolled sorting / filtering / pagination outside the table. -Correct: register the matching `*Feature` in `_features`, register its row-model factory in `_rowModels`, and use the feature APIs (`setSorting`, `setColumnFilters`, etc.). This is the #1 AI tell. +Correct: register the matching `*Feature` in `features`, register its row-model factory in `rowModels`, and use the feature APIs (`setSorting`, `setColumnFilters`, etc.). This is the #1 AI tell. Source: `docs/guide/features.md`. ### MEDIUM Passing the same slice via `atoms` AND `state` diff --git a/packages/lit-table/src/TableController.ts b/packages/lit-table/src/TableController.ts index 447b30be9f..c3a67f2940 100644 --- a/packages/lit-table/src/TableController.ts +++ b/packages/lit-table/src/TableController.ts @@ -119,13 +119,13 @@ export type LitTable< * ```ts * @customElement('my-table') * class MyTable extends LitElement { - * private tableController = new TableController(this) + * private tableController = new TableController(this) * * protected render() { * const table = this.tableController.table( * { - * _features, - * _rowModels: {}, + * features, + * rowModels: {}, * columns, * data, * }, @@ -162,7 +162,7 @@ export class TableController< * @example * ```ts * const table = this.tableController.table( - * { _features, _rowModels: {}, columns, data }, + * { features, rowModels: {}, columns, data }, * (state) => ({ sorting: state.sorting }), * ) * ``` @@ -174,9 +174,9 @@ export class TableController< if (!this._table) { const mergedOptions: TableOptions = { ...tableOptions, - _features: { + features: { coreReativityFeature: litReactivity(), - ...tableOptions._features, + ...tableOptions.features, }, mergeOptions: ( defaultOptions: TableOptions, diff --git a/packages/lit-table/src/createTableHook.ts b/packages/lit-table/src/createTableHook.ts index 8fdd161934..76cd286b87 100644 --- a/packages/lit-table/src/createTableHook.ts +++ b/packages/lit-table/src/createTableHook.ts @@ -369,12 +369,12 @@ export type AppLitTable< * useCellContext, * useHeaderContext, * } = createTableHook({ - * _features: tableFeatures({ + * features: tableFeatures({ * rowPaginationFeature, * rowSortingFeature, * columnFilteringFeature, * }), - * _rowModels: { + * rowModels: { * paginatedRowModel: createPaginatedRowModel(), * sortedRowModel: createSortedRowModel(sortFns), * filteredRowModel: createFilteredRowModel(filterFns), @@ -619,7 +619,7 @@ export function createTableHook< host: ReactiveControllerHost & HTMLElement, tableOptions: Omit< TableOptions, - '_features' | '_rowModels' + 'features' | 'rowModels' >, selector?: (state: TableState) => TSelected, ): { @@ -767,7 +767,7 @@ export function createTableHook< } return { - appFeatures: defaultTableOptions._features as TFeatures, + appFeatures: defaultTableOptions.features as TFeatures, createAppColumnHelper, useAppTable, useTableContext, diff --git a/packages/lit-table/tests/unit/defaultReactivity.test.ts b/packages/lit-table/tests/unit/defaultReactivity.test.ts index 9d8e572681..f30eedf604 100644 --- a/packages/lit-table/tests/unit/defaultReactivity.test.ts +++ b/packages/lit-table/tests/unit/defaultReactivity.test.ts @@ -10,8 +10,8 @@ describe('TableController', () => { const controller = new TableController(host) const table = controller.table({ - _features: {}, - _rowModels: {}, + features: {}, + rowModels: {}, columns: [], data: [], }) diff --git a/packages/preact-table-devtools/skills/preact/compose-with-tanstack-devtools/SKILL.md b/packages/preact-table-devtools/skills/preact/compose-with-tanstack-devtools/SKILL.md index a03a243cf2..b9d2f6d94b 100644 --- a/packages/preact-table-devtools/skills/preact/compose-with-tanstack-devtools/SKILL.md +++ b/packages/preact-table-devtools/skills/preact/compose-with-tanstack-devtools/SKILL.md @@ -47,8 +47,8 @@ import { function UsersScreen() { const table = useTable({ - _features, - _rowModels, + features, + rowModels, key: 'users-table', columns, data, diff --git a/packages/preact-table/skills/preact/client-to-server/SKILL.md b/packages/preact-table/skills/preact/client-to-server/SKILL.md index ae87454d74..dfd4e316c8 100644 --- a/packages/preact-table/skills/preact/client-to-server/SKILL.md +++ b/packages/preact-table/skills/preact/client-to-server/SKILL.md @@ -25,7 +25,7 @@ sources: - TanStack/table:docs/framework/preact/guide/table-state.md --- -Client-side tables run sort/filter/paginate through registered row-model factories. Server-side tables let the server own those stages; the table just renders what the server returned and emits state changes that the app uses to refetch. Same `_features`, same APIs — different ownership. +Client-side tables run sort/filter/paginate through registered row-model factories. Server-side tables let the server own those stages; the table just renders what the server returned and emits state changes that the app uses to refetch. Same `features`, same APIs — different ownership. ## The Manual Flags @@ -39,7 +39,7 @@ Set the matching flag(s) to `true` to tell the table that the server (not the re | `manualGrouping` | group-by rows | | `manualExpanding` | row expansion | -The matching `*Feature` should still be in `_features` so its state slice exists and its APIs work — you are only telling the row-model pipeline to skip the transform. +The matching `*Feature` should still be in `features` so its state slice exists and its APIs work — you are only telling the row-model pipeline to skip the transform. For pagination, supply `rowCount` so `table.getPageCount()` is correct. Optional but usually required for a UI. @@ -59,7 +59,7 @@ import { type PaginationState, } from '@tanstack/preact-table' -const _features = tableFeatures({ rowPaginationFeature }) +const features = tableFeatures({ rowPaginationFeature }) function App() { const paginationAtom = useCreateAtom({ @@ -78,8 +78,8 @@ function App() { const table = useTable( { - _features, - _rowModels: {}, // no client-side pagination factory + features, + rowModels: {}, // no client-side pagination factory columns, data: rowsPayload?.rows ?? defaultData, rowCount: rowsPayload?.rowCount, // makes getPageCount() correct @@ -99,7 +99,7 @@ Source: `examples/preact/with-tanstack-query/src/main.tsx` (lines 56–86). Same shape, more atoms. Compose `pagination + sorting + columnFilters + globalFilter` into the request key. ```tsx -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, rowSortingFeature, columnFilteringFeature, @@ -126,8 +126,8 @@ const { data } = useSomeServerFetcher({ }) const table = useTable({ - _features, - _rowModels: {}, // server owns every stage + features, + rowModels: {}, // server owns every stage columns, data: data?.rows ?? EMPTY, rowCount: data?.rowCount, @@ -153,8 +153,8 @@ Wrong: ```tsx useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data: response?.rows ?? [], atoms: { pagination: paginationAtom }, @@ -168,8 +168,8 @@ Correct: ```tsx useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data: response?.rows ?? [], rowCount: response?.rowCount, @@ -187,8 +187,8 @@ Wrong: ```tsx useTable({ - _features, - _rowModels: { paginatedRowModel: createPaginatedRowModel() }, // still runs + features, + rowModels: { paginatedRowModel: createPaginatedRowModel() }, // still runs data: server.rows, manualPagination: true, }) @@ -198,8 +198,8 @@ Correct: ```tsx useTable({ - _features, - _rowModels: {}, // server owns pagination + features, + rowModels: {}, // server owns pagination data: server.rows, rowCount: server.rowCount, manualPagination: true, @@ -251,8 +251,8 @@ const { data } = useQuery({ }) const table = useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data: data?.rows ?? defaultData, rowCount: data?.rowCount, @@ -263,15 +263,15 @@ const table = useTable({ Source: `examples/preact/with-tanstack-query/src/main.tsx`. -### MEDIUM Removing the matching feature from `_features` +### MEDIUM Removing the matching feature from `features` Wrong: ```tsx -const _features = tableFeatures({}) // dropped rowPaginationFeature +const features = tableFeatures({}) // dropped rowPaginationFeature useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, data: server.rows, rowCount: server.rowCount, manualPagination: true, @@ -282,7 +282,7 @@ table.setPageIndex(0) // type error / no-op Correct: keep the feature registered. `manualPagination: true` only tells the row-model pipeline to skip slicing — you still want the pagination state slice and `setPageIndex` / `nextPage` APIs. ```tsx -const _features = tableFeatures({ rowPaginationFeature }) +const features = tableFeatures({ rowPaginationFeature }) ``` Source: `docs/guide/features.md`. diff --git a/packages/preact-table/skills/preact/compose-with-tanstack-form/SKILL.md b/packages/preact-table/skills/preact/compose-with-tanstack-form/SKILL.md index bc586d613e..1c25186f6e 100644 --- a/packages/preact-table/skills/preact/compose-with-tanstack-form/SKILL.md +++ b/packages/preact-table/skills/preact/compose-with-tanstack-form/SKILL.md @@ -99,13 +99,13 @@ import { useAppForm } from './form-hook' type Person = { id: string; firstName: string; age: number } -const _features = tableFeatures({}) -const columnHelper = createColumnHelper() +const features = tableFeatures({}) +const columnHelper = createColumnHelper() function EditableTable({ data }: { data: Person[] }) { const table = useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns: columnHelper.columns([ columnHelper.accessor('firstName', { header: 'First Name', @@ -187,15 +187,15 @@ The bulk-edit alternative is a single top-level form with ` row.id, diff --git a/packages/preact-table/skills/preact/compose-with-tanstack-pacer/SKILL.md b/packages/preact-table/skills/preact/compose-with-tanstack-pacer/SKILL.md index b4fae99e2c..cf94393a09 100644 --- a/packages/preact-table/skills/preact/compose-with-tanstack-pacer/SKILL.md +++ b/packages/preact-table/skills/preact/compose-with-tanstack-pacer/SKILL.md @@ -172,7 +172,7 @@ Correct: debounce the **write** (`column.setFilterValue`) — that's what trigge Wrong: debouncing every `useTable` call. -Correct: pacer doesn't fix unstable `_features` / `columns` / `data` references. Stabilize those first; reach for pacer for input/scroll/resize hotspots. +Correct: pacer doesn't fix unstable `features` / `columns` / `data` references. Stabilize those first; reach for pacer for input/scroll/resize hotspots. Source: `docs/framework/preact/guide/table-state.md` (FAQ #1). ### MEDIUM Forgetting that debounce delays the trailing edge diff --git a/packages/preact-table/skills/preact/compose-with-tanstack-query/SKILL.md b/packages/preact-table/skills/preact/compose-with-tanstack-query/SKILL.md index fa68d3bf7b..a2e0b96984 100644 --- a/packages/preact-table/skills/preact/compose-with-tanstack-query/SKILL.md +++ b/packages/preact-table/skills/preact/compose-with-tanstack-query/SKILL.md @@ -55,8 +55,8 @@ import { fetchData } from './fetchData' import type { Person } from './fetchData' const queryClient = new QueryClient() -const _features = tableFeatures({ rowPaginationFeature }) -const columnHelper = createColumnHelper() +const features = tableFeatures({ rowPaginationFeature }) +const columnHelper = createColumnHelper() const columns = columnHelper.columns([ columnHelper.accessor('firstName', { @@ -84,8 +84,8 @@ function App() { const table = useTable( { - _features, - _rowModels: {}, // server owns slicing + features, + rowModels: {}, // server owns slicing columns, data: dataQuery.data?.rows ?? defaultData, rowCount: dataQuery.data?.rowCount, @@ -142,7 +142,7 @@ Source: `examples/preact/with-tanstack-query/src/fetchData.ts`. Add more external atoms; include them in the `queryKey`; set the matching `manual*` flag. The server's fetcher accepts whatever shape you forward. ```tsx -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, rowSortingFeature, columnFilteringFeature, @@ -170,8 +170,8 @@ const dataQuery = useQuery({ }) const table = useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data: dataQuery.data?.rows ?? defaultData, rowCount: dataQuery.data?.rowCount, @@ -254,14 +254,14 @@ useTable({ /* … */, data: dataQuery.data?.rows ?? defaultData }) A new empty array each render busts row-model memos. -### HIGH Keeping the client-side `_rowModels` when manual +### HIGH Keeping the client-side `rowModels` when manual Wrong: ```tsx useTable({ - _features, - _rowModels: { paginatedRowModel: createPaginatedRowModel() }, // wasted work + features, + rowModels: { paginatedRowModel: createPaginatedRowModel() }, // wasted work /* … */, manualPagination: true, }) diff --git a/packages/preact-table/skills/preact/compose-with-tanstack-store/SKILL.md b/packages/preact-table/skills/preact/compose-with-tanstack-store/SKILL.md index 114485bd45..fe86048a99 100644 --- a/packages/preact-table/skills/preact/compose-with-tanstack-store/SKILL.md +++ b/packages/preact-table/skills/preact/compose-with-tanstack-store/SKILL.md @@ -52,7 +52,7 @@ import { type SortingState, } from '@tanstack/preact-table' -const _features = tableFeatures({ rowPaginationFeature, rowSortingFeature }) +const features = tableFeatures({ rowPaginationFeature, rowSortingFeature }) function PeopleTable({ data }) { // Stable atoms owned by this component. @@ -67,8 +67,8 @@ function PeopleTable({ data }) { const pagination = useSelector(paginationAtom) const table = useTable({ - _features, - _rowModels: { + features, + rowModels: { /* … */ }, columns, @@ -100,8 +100,8 @@ export const selectionAtom = createAtom({}) import { selectionAtom } from '../shared/atoms' const table = useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, atoms: { rowSelection: selectionAtom }, diff --git a/packages/preact-table/skills/preact/compose-with-tanstack-virtual/SKILL.md b/packages/preact-table/skills/preact/compose-with-tanstack-virtual/SKILL.md index d7113bfce5..8ab4c8360d 100644 --- a/packages/preact-table/skills/preact/compose-with-tanstack-virtual/SKILL.md +++ b/packages/preact-table/skills/preact/compose-with-tanstack-virtual/SKILL.md @@ -62,7 +62,7 @@ import { } from '@tanstack/preact-table' import type { JSX } from 'preact' -const _features = tableFeatures({ rowSortingFeature }) +const features = tableFeatures({ rowSortingFeature }) // Minimal Preact hook around the framework-agnostic Virtualizer. function useVirtualizer( @@ -109,8 +109,8 @@ function useVirtualizer( function BigTable({ data }) { const table = useTable( { - _features, - _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, data, }, diff --git a/packages/preact-table/skills/preact/getting-started/SKILL.md b/packages/preact-table/skills/preact/getting-started/SKILL.md index 38a73a1997..01ecd79d96 100644 --- a/packages/preact-table/skills/preact/getting-started/SKILL.md +++ b/packages/preact-table/skills/preact/getting-started/SKILL.md @@ -2,11 +2,11 @@ name: preact/getting-started description: > End-to-end first-table journey for `@tanstack/preact-table` v9: install the - adapter, declare `_features` via `tableFeatures()`, declare `_rowModels` with + adapter, declare `features` via `tableFeatures()`, declare `rowModels` with their factories and *Fns parameters, build a typed column helper, call `useTable` with stable references, and render with `table.FlexRender`. Routing keywords: install preact-table, first table, getting started, - tableFeatures, _features, _rowModels, useTable, FlexRender, basic-use-table. + tableFeatures, features, rowModels, useTable, FlexRender, basic-use-table. type: lifecycle library: tanstack-table framework: preact @@ -37,9 +37,9 @@ Peer dependency: `preact >=10`. Source: `packages/preact-table/package.json`. -## Step 1 — Declare `_features` +## Step 1 — Declare `features` -v9 is explicit about what a table uses. `_features` is a registry of every feature the table needs. Use `tableFeatures({...})` to get an object whose TypeScript shape drives state inference, API surface, and tree-shaking. +v9 is explicit about what a table uses. `features` is a registry of every feature the table needs. Use `tableFeatures({...})` to get an object whose TypeScript shape drives state inference, API surface, and tree-shaking. ```tsx import { @@ -48,19 +48,19 @@ import { rowSortingFeature, } from '@tanstack/preact-table' -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, rowSortingFeature, }) ``` -If `_features` does not include `rowSelectionFeature`, then `table.atoms.rowSelection`, `table.setRowSelection`, `table.getIsAllRowsSelected()`, etc. all become TypeScript errors — and the runtime won't ship that logic. Pass `tableFeatures({})` for a minimum-overhead table with just the core row model. +If `features` does not include `rowSelectionFeature`, then `table.atoms.rowSelection`, `table.setRowSelection`, `table.getIsAllRowsSelected()`, etc. all become TypeScript errors — and the runtime won't ship that logic. Pass `tableFeatures({})` for a minimum-overhead table with just the core row model. Source: `docs/framework/preact/preact-table.md`; `docs/guide/features.md`. -## Step 2 — Declare `_rowModels` +## Step 2 — Declare `rowModels` -Each registered feature that needs a row-model stage maps to a factory under `_rowModels`. The factory takes a record of \*Fns (predicates, comparators, etc.) for that stage. +Each registered feature that needs a row-model stage maps to a factory under `rowModels`. The factory takes a record of \*Fns (predicates, comparators, etc.) for that stage. ```tsx import { @@ -69,19 +69,19 @@ import { sortFns, } from '@tanstack/preact-table' -const _rowModels = { +const rowModels = { paginatedRowModel: createPaginatedRowModel(), sortedRowModel: createSortedRowModel(sortFns), } ``` -The core row model is always included — `_rowModels: {}` is valid for a feature-free table. +The core row model is always included — `rowModels: {}` is valid for a feature-free table. Source: `docs/framework/preact/preact-table.md`. ## Step 3 — Type your data and build columns -Declare your row shape once and feed it to `createColumnHelper()`. This is the type-safe path; `ColumnDef[]` also works. +Declare your row shape once and feed it to `createColumnHelper()`. This is the type-safe path; `ColumnDef[]` also works. ```tsx import { createColumnHelper, type ColumnDef } from '@tanstack/preact-table' @@ -95,7 +95,7 @@ type Person = { progress: number } -const columnHelper = createColumnHelper() +const columnHelper = createColumnHelper() const columns = columnHelper.columns([ columnHelper.accessor('firstName', { @@ -145,8 +145,8 @@ function App() { const table = useTable( { - _features, - _rowModels, + features, + rowModels, columns, data, debugTable: true, @@ -211,13 +211,13 @@ For starting values, use `initialState`. For controlled slices, use `atoms` (pre ## Common Mistakes -### CRITICAL Calling a feature API when the feature is not in `_features` +### CRITICAL Calling a feature API when the feature is not in `features` Wrong: ```tsx -const _features = tableFeatures({}) // no rowPaginationFeature -const table = useTable({ _features, _rowModels: {}, columns, data }) +const features = tableFeatures({}) // no rowPaginationFeature +const table = useTable({ features, rowModels: {}, columns, data }) table.setPageIndex(0) // TypeScript error AND runtime no-op ``` @@ -225,10 +225,10 @@ table.setPageIndex(0) // TypeScript error AND runtime no-op Correct: ```tsx -const _features = tableFeatures({ rowPaginationFeature }) +const features = tableFeatures({ rowPaginationFeature }) const table = useTable({ - _features, - _rowModels: { paginatedRowModel: createPaginatedRowModel() }, + features, + rowModels: { paginatedRowModel: createPaginatedRowModel() }, columns, data, }) @@ -244,8 +244,8 @@ Source: `docs/guide/features.md`; `docs/framework/preact/guide/table-state.md`. Wrong: ```tsx -const _features = tableFeatures({ rowSortingFeature }) -const table = useTable({ _features, _rowModels: {}, columns, data }) +const features = tableFeatures({ rowSortingFeature }) +const table = useTable({ features, rowModels: {}, columns, data }) table.setSorting([{ id: 'age', desc: true }]) // table.getRowModel().rows is still unsorted — no sortedRowModel registered ``` @@ -253,45 +253,45 @@ table.setSorting([{ id: 'age', desc: true }]) Correct: ```tsx -const _features = tableFeatures({ rowSortingFeature }) +const features = tableFeatures({ rowSortingFeature }) const table = useTable({ - _features, - _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, data, }) ``` -Each row-model feature (sorting, filtering, pagination, grouping, expanding, faceting) requires its row-model factory in `_rowModels` to actually transform the rows. +Each row-model feature (sorting, filtering, pagination, grouping, expanding, faceting) requires its row-model factory in `rowModels` to actually transform the rows. Source: `docs/framework/preact/preact-table.md`. -### HIGH Unstable `_features` / `columns` / `data` references +### HIGH Unstable `features` / `columns` / `data` references Wrong: ```tsx function MyTable({ rows }) { - const _features = tableFeatures({ rowSortingFeature }) // new every render + const features = tableFeatures({ rowSortingFeature }) // new every render const columns = [ /* … */ ] // new every render const data = rows ?? [] // new [] every render - const table = useTable({ _features, _rowModels: {}, columns, data }) + const table = useTable({ features, rowModels: {}, columns, data }) } ``` Correct: ```tsx -const _features = tableFeatures({ rowSortingFeature }) -const columns: ColumnDef[] = [ +const features = tableFeatures({ rowSortingFeature }) +const columns: ColumnDef[] = [ /* … */ ] const EMPTY: Person[] = [] function MyTable({ rows }) { const data = rows ?? EMPTY - const table = useTable({ _features, _rowModels: {}, columns, data }) + const table = useTable({ features, rowModels: {}, columns, data }) } ``` @@ -309,10 +309,10 @@ const sorted = useMemo(() => [...data].sort(/* … */), [data, sorting]) // dupl Correct: ```tsx -const _features = tableFeatures({ rowSortingFeature }) +const features = tableFeatures({ rowSortingFeature }) const table = useTable({ - _features, - _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, data, }) @@ -351,17 +351,17 @@ import { sortFns, } from '@tanstack/preact-table' -const _features = tableFeatures({ rowSortingFeature }) +const features = tableFeatures({ rowSortingFeature }) const table = useTable({ - _features, - _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, data, }) ``` -v8 used `useReactTable` and `get*RowModel` options. v9 uses `useTable` plus `_features` + `_rowModels`. See `tanstack-table/preact/migrate-v8-to-v9` for the full mapping. +v8 used `useReactTable` and `get*RowModel` options. v9 uses `useTable` plus `features` + `rowModels`. See `tanstack-table/preact/migrate-v8-to-v9` for the full mapping. Source: `docs/framework/preact/preact-table.md`. ## See Also diff --git a/packages/preact-table/skills/preact/migrate-v8-to-v9/SKILL.md b/packages/preact-table/skills/preact/migrate-v8-to-v9/SKILL.md index 4a36534737..5e72d16849 100644 --- a/packages/preact-table/skills/preact/migrate-v8-to-v9/SKILL.md +++ b/packages/preact-table/skills/preact/migrate-v8-to-v9/SKILL.md @@ -5,10 +5,10 @@ description: > `@tanstack/preact-table`. Maps every old-shaped option, helper, type, and method an agent will reproduce from v8 muscle memory to its v9 equivalent: `useReactTable` → `useTable`, per-row-model `get*RowModel` options → - `_features` + `_rowModels`, plain column helpers → typed column helpers, + `features` + `rowModels`, plain column helpers → typed column helpers, `state` + `on*Change` → `atoms`, `flexRender` → `table.FlexRender`, and core type renames. Routing keywords: v8 to v9, migration, useReactTable, table - v8 preact, get*RowModel, _features. + v8 preact, get*RowModel, features. type: lifecycle library: tanstack-table framework: preact @@ -28,21 +28,21 @@ The Preact adapter mirrors the React v9 surface, so any v8 → v9 migration guid ## The Core Mapping -| v8 (Preact / React-compatible) | v9 (`@tanstack/preact-table`) | -| ------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `useReactTable(opts)` | `useTable(opts, selector?)` | -| `getCoreRowModel: getCoreRowModel()` | included by default — `_rowModels: {}` is valid | -| `getSortedRowModel: getSortedRowModel()` | `_features: { rowSortingFeature }` + `_rowModels: { sortedRowModel: createSortedRowModel(sortFns) }` | -| `getFilteredRowModel: getFilteredRowModel()` | `_features: { columnFilteringFeature, globalFilteringFeature }` + `_rowModels: { filteredRowModel: createFilteredRowModel(filterFns) }` | -| `getPaginationRowModel: getPaginationRowModel()` | `_features: { rowPaginationFeature }` + `_rowModels: { paginatedRowModel: createPaginatedRowModel() }` | -| `getGroupedRowModel: getGroupedRowModel()` | `_features: { columnGroupingFeature }` + `_rowModels: { groupedRowModel: createGroupedRowModel(aggregationFns) }` | -| `getExpandedRowModel: getExpandedRowModel()` | `_features: { rowExpandingFeature }` + `_rowModels: { expandedRowModel: createExpandedRowModel() }` | -| `getFacetedRowModel`, `getFacetedUniqueValues`, `getFacetedMinMaxValues` | `_features: { columnFacetingFeature, globalFacetingFeature }` + `_rowModels: { facetedRowModel: createFacetedRowModel(facetedFns), facetedUniqueValues: createFacetedUniqueValues(), facetedMinMaxValues: createFacetedMinMaxValues() }` | -| `flexRender(def, ctx)` | `` / `header={...}` / `footer={...}` | -| `state`, `on*Change` (only) | still supported, plus `atoms` (preferred per slice) | -| `createColumnHelper()` | `createColumnHelper()` — both generics required | -| `ColumnDef` | `ColumnDef` — `TFeatures` is now the first generic | -| `Table` | `Table` | +| v8 (Preact / React-compatible) | v9 (`@tanstack/preact-table`) | +| ------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `useReactTable(opts)` | `useTable(opts, selector?)` | +| `getCoreRowModel: getCoreRowModel()` | included by default — `rowModels: {}` is valid | +| `getSortedRowModel: getSortedRowModel()` | `features: { rowSortingFeature }` + `rowModels: { sortedRowModel: createSortedRowModel(sortFns) }` | +| `getFilteredRowModel: getFilteredRowModel()` | `features: { columnFilteringFeature, globalFilteringFeature }` + `rowModels: { filteredRowModel: createFilteredRowModel(filterFns) }` | +| `getPaginationRowModel: getPaginationRowModel()` | `features: { rowPaginationFeature }` + `rowModels: { paginatedRowModel: createPaginatedRowModel() }` | +| `getGroupedRowModel: getGroupedRowModel()` | `features: { columnGroupingFeature }` + `rowModels: { groupedRowModel: createGroupedRowModel(aggregationFns) }` | +| `getExpandedRowModel: getExpandedRowModel()` | `features: { rowExpandingFeature }` + `rowModels: { expandedRowModel: createExpandedRowModel() }` | +| `getFacetedRowModel`, `getFacetedUniqueValues`, `getFacetedMinMaxValues` | `features: { columnFacetingFeature, globalFacetingFeature }` + `rowModels: { facetedRowModel: createFacetedRowModel(facetedFns), facetedUniqueValues: createFacetedUniqueValues(), facetedMinMaxValues: createFacetedMinMaxValues() }` | +| `flexRender(def, ctx)` | `` / `header={...}` / `footer={...}` | +| `state`, `on*Change` (only) | still supported, plus `atoms` (preferred per slice) | +| `createColumnHelper()` | `createColumnHelper()` — both generics required | +| `ColumnDef` | `ColumnDef` — `TFeatures` is now the first generic | +| `Table` | `Table` | Source: `docs/framework/preact/preact-table.md`; `docs/framework/preact/guide/table-state.md`. @@ -71,7 +71,7 @@ import { } from '@tanstack/preact-table' ``` -### 2. Declare `_features` and `_rowModels` +### 2. Declare `features` and `rowModels` Replace each `get*RowModel: get*RowModel()` option with a feature import + a row-model factory. @@ -87,15 +87,15 @@ const table = useReactTable({ }) // v9 -const _features = tableFeatures({ +const features = tableFeatures({ rowSortingFeature, columnFilteringFeature, rowPaginationFeature, }) const table = useTable({ - _features, - _rowModels: { + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns), filteredRowModel: createFilteredRowModel(filterFns), paginatedRowModel: createPaginatedRowModel(), @@ -105,7 +105,7 @@ const table = useTable({ }) ``` -Move `_features` to module scope. Reference stability matters — see `tanstack-table/preact/production-readiness`. +Move `features` to module scope. Reference stability matters — see `tanstack-table/preact/production-readiness`. ### 3. Update column types and helpers @@ -119,11 +119,12 @@ const columns: ColumnDef[] = columnHelper.columns([ ]) // v9 -const columnHelper = createColumnHelper() -const columns: Array> = - columnHelper.columns([ +const columnHelper = createColumnHelper() +const columns: Array> = columnHelper.columns( + [ /* … */ - ]) + ], +) ``` ### 4. Replace `flexRender` calls with `table.FlexRender` @@ -150,8 +151,8 @@ Source: `packages/preact-table/src/FlexRender.tsx`. // v8 / v9 fallback const [sorting, setSorting] = useState([]) const table = useTable({ - _features, - _rowModels, + features, + rowModels, columns, data, state: { sorting }, @@ -162,8 +163,8 @@ const table = useTable({ import { useCreateAtom } from '@tanstack/preact-store' const sortingAtom = useCreateAtom([]) const table = useTable({ - _features, - _rowModels, + features, + rowModels, columns, data, atoms: { sorting: sortingAtom }, @@ -187,8 +188,8 @@ Wrong: ```tsx const table = useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, getSortedRowModel: getSortedRowModel(), // v8 leftover — silently ignored @@ -199,16 +200,16 @@ table.setSorting([{ id: 'age', desc: true }]) // rows are NOT sorted Correct: ```tsx -const _features = tableFeatures({ rowSortingFeature }) +const features = tableFeatures({ rowSortingFeature }) const table = useTable({ - _features, - _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, data, }) ``` -v9 doesn't read the `get*RowModel` options. The row model only runs for stages registered in `_rowModels`, and the feature only mounts if it is in `_features`. +v9 doesn't read the `get*RowModel` options. The row model only runs for stages registered in `rowModels`, and the feature only mounts if it is in `features`. Source: `docs/framework/preact/preact-table.md`. ### CRITICAL Forgetting to register a feature whose API you are calling @@ -216,8 +217,8 @@ Source: `docs/framework/preact/preact-table.md`. Wrong: ```tsx -const _features = tableFeatures({}) // no rowSelectionFeature -const table = useTable({ _features, _rowModels: {}, columns, data }) +const features = tableFeatures({}) // no rowSelectionFeature +const table = useTable({ features, rowModels: {}, columns, data }) table.getIsAllRowsSelected() // TypeScript error / runtime no-op row.toggleSelected(true) // same ``` @@ -225,10 +226,10 @@ row.toggleSelected(true) // same Correct: ```tsx -const _features = tableFeatures({ rowSelectionFeature }) +const features = tableFeatures({ rowSelectionFeature }) const table = useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, enableRowSelection: true, @@ -245,8 +246,8 @@ Wrong: ```tsx const table = useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, getCoreRowModel: getCoreRowModel(), // no-op in v9 @@ -256,7 +257,7 @@ const table = useTable({ Correct: ```tsx -const table = useTable({ _features, _rowModels: {}, columns, data }) +const table = useTable({ features, rowModels: {}, columns, data }) ``` The core row model is always included in v9. There is no `getCoreRowModel` option. @@ -276,8 +277,8 @@ const columns: ColumnDef[] = [ Correct: ```tsx -const columnHelper = createColumnHelper() -const columns: Array> = [ +const columnHelper = createColumnHelper() +const columns: Array> = [ /* … */ ] ``` @@ -293,7 +294,7 @@ Wrong: // Manual sorting, manual filtering, manual pagination, manual row-selection objects ``` -Correct: register the matching feature in `_features`, register its factory in `_rowModels`, and use the feature API. v9 ships built-ins for sorting, filtering, pagination, grouping, expanding, faceting, row selection, column visibility/order/pinning/sizing, and row pinning. +Correct: register the matching feature in `features`, register its factory in `rowModels`, and use the feature API. v9 ships built-ins for sorting, filtering, pagination, grouping, expanding, faceting, row selection, column visibility/order/pinning/sizing, and row pinning. Source: `docs/guide/features.md`. ### MEDIUM Calling `flexRender` directly when grouping is on diff --git a/packages/preact-table/skills/preact/production-readiness/SKILL.md b/packages/preact-table/skills/preact/production-readiness/SKILL.md index 2cbcc07a3e..c62e297f80 100644 --- a/packages/preact-table/skills/preact/production-readiness/SKILL.md +++ b/packages/preact-table/skills/preact/production-readiness/SKILL.md @@ -2,8 +2,8 @@ name: preact/production-readiness description: > Ship-ready optimizations for `@tanstack/preact-table` v9: tree-shake the - bundle by registering ONLY the `_features` you actually use; memoize - `_features`, `data`, and `columns` for stable identity; replace + bundle by registering ONLY the `features` you actually use; memoize + `features`, `data`, and `columns` for stable identity; replace `(state) => state` with narrow selectors or per-slice `useSelector` subscriptions; wrap hot subtrees in ``; and prefer slice atoms over `state` + `on*Change` for fine-grained updates. Routing keywords: @@ -27,13 +27,13 @@ sources: This skill collects the production-readiness levers for a Preact v9 table. Each one is independent — apply only the ones whose problem you actually have. -## 1. Tree-Shake `_features` +## 1. Tree-Shake `features` -Only register features the table actually uses. v9's bundle savings come from `_features` controlling which feature code (and which state slices and APIs) get included. +Only register features the table actually uses. v9's bundle savings come from `features` controlling which feature code (and which state slices and APIs) get included. ```tsx // Bad — pulls every feature into the bundle even if the UI never uses them. -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, rowSortingFeature, rowSelectionFeature, @@ -51,32 +51,32 @@ const _features = tableFeatures({ }) // Good — feature list matches what the UI exposes. -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, rowSortingFeature, rowSelectionFeature, }) ``` -Same idea for `_rowModels` — only register the row-model factory for features that need one and that you have registered. +Same idea for `rowModels` — only register the row-model factory for features that need one and that you have registered. Source: `docs/guide/features.md`; `docs/framework/preact/preact-table.md`. -## 2. Stable References for `_features`, `columns`, `data`, `_rowModels` +## 2. Stable References for `features`, `columns`, `data`, `rowModels` Identity drives every internal memo. Declare these at module scope when possible; otherwise wrap with `useMemo`. ```tsx // Best — module scope. Single allocation. -const _features = tableFeatures({ rowSortingFeature }) -const columns: Array> = [ +const features = tableFeatures({ rowSortingFeature }) +const columns: Array> = [ /* … */ ] const EMPTY: Person[] = [] function MyTable({ rows }: { rows: Person[] | undefined }) { const data = rows ?? EMPTY - const table = useTable({ _features, _rowModels: {}, columns, data }) + const table = useTable({ features, rowModels: {}, columns, data }) } // Okay — useMemo for dynamic columns. @@ -181,8 +181,8 @@ Use `initialState` for starting values. Setting state in an effect after mount t ```tsx const table = useTable({ - _features, - _rowModels: { + features, + rowModels: { /* … */ }, columns, @@ -198,7 +198,7 @@ Source: `docs/framework/preact/guide/table-state.md`. ## 7. Reach for `createTableHook` for Multi-Table Apps -When several screens share the same `_features`, `_rowModels`, and conventions, `createTableHook` centralizes the configuration and lets you ship pre-bound cell/header components. Tables collapse to columns + data. +When several screens share the same `features`, `rowModels`, and conventions, `createTableHook` centralizes the configuration and lets you ship pre-bound cell/header components. Tables collapse to columns + data. Source: `docs/framework/preact/guide/create-table-hook.md`. @@ -210,22 +210,22 @@ Wrong: ```tsx function MyTable() { - const _features = tableFeatures({ rowSortingFeature }) // new object every render - useTable({ _features, _rowModels: {}, columns, data }) + const features = tableFeatures({ rowSortingFeature }) // new object every render + useTable({ features, rowModels: {}, columns, data }) } ``` Correct: ```tsx -const _features = tableFeatures({ rowSortingFeature }) // module scope +const features = tableFeatures({ rowSortingFeature }) // module scope function MyTable() { - useTable({ _features, _rowModels: {}, columns, data }) + useTable({ features, rowModels: {}, columns, data }) } ``` -A new `_features` reference each render busts every memo that keys off it. +A new `features` reference each render busts every memo that keys off it. Source: `docs/framework/preact/guide/table-state.md` (FAQ #1). ### CRITICAL Reimplementing built-ins manually @@ -239,10 +239,10 @@ const sorted = useMemo(() => [...data].sort(/* … */), [data, sorting]) Correct: ```tsx -const _features = tableFeatures({ rowSortingFeature }) +const features = tableFeatures({ rowSortingFeature }) const table = useTable({ - _features, - _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, data, }) diff --git a/packages/preact-table/skills/preact/table-state/SKILL.md b/packages/preact-table/skills/preact/table-state/SKILL.md index 2abd73ba0f..11d562ae60 100644 --- a/packages/preact-table/skills/preact/table-state/SKILL.md +++ b/packages/preact-table/skills/preact/table-state/SKILL.md @@ -36,7 +36,7 @@ This skill builds on `tanstack-table/state-management` and `tanstack-table/setup ## Setup -Every Preact v9 table follows the same shape. Define `_features`, `_rowModels`, and `columns` at module scope so their references are stable, then call `useTable` and render with ``. +Every Preact v9 table follows the same shape. Define `features`, `rowModels`, and `columns` at module scope so their references are stable, then call `useTable` and render with ``. ```tsx import { render } from 'preact' @@ -53,8 +53,8 @@ import { type Person = { firstName: string; lastName: string; age: number } // Module-scope = stable identity. Critical for re-render perf. -const _features = tableFeatures({ rowSortingFeature }) -const columnHelper = createColumnHelper() +const features = tableFeatures({ rowSortingFeature }) +const columnHelper = createColumnHelper() const columns = columnHelper.columns([ columnHelper.accessor('firstName', { header: 'First' }), @@ -65,8 +65,8 @@ const columns = columnHelper.columns([ function PeopleTable({ data }: { data: Person[] }) { const table = useTable( { - _features, - _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, data, }, @@ -116,8 +116,8 @@ The Preact adapter uses `useSelector` from `@tanstack/preact-store` with `shallo // Narrow selector — re-render only on sorting/pagination changes. const table = useTable( { - _features, - _rowModels: { + features, + rowModels: { /*…*/ }, columns, @@ -205,8 +205,8 @@ function MyTable({ data }) { const pagination = useSelector(paginationAtom) const table = useTable({ - _features, - _rowModels: { + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns), paginatedRowModel: createPaginatedRowModel(), }, @@ -222,7 +222,7 @@ Source: `examples/preact/basic-external-atoms/src/main.tsx`. ### 4. External state with `state` + `on*Change` and `createTableHook` -Classic `useState` + `on*Change` integration (v8 migration paths) and the `createTableHook` factory for packaging shared `_features` / `_rowModels` / cell components into `useAppTable` + `createAppColumnHelper` + `table.AppTable` / `AppHeader` / `AppCell` / `AppFooter` boundaries — see [advanced-state-patterns.md](references/advanced-state-patterns.md). +Classic `useState` + `on*Change` integration (v8 migration paths) and the `createTableHook` factory for packaging shared `features` / `rowModels` / cell components into `useAppTable` + `createAppColumnHelper` + `table.AppTable` / `AppHeader` / `AppCell` / `AppFooter` boundaries — see [advanced-state-patterns.md](references/advanced-state-patterns.md). ## Common Mistakes @@ -261,8 +261,8 @@ Wrong: ```tsx const table = useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, atoms: { pagination: paginationAtom }, @@ -275,8 +275,8 @@ Correct: ```tsx const table = useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, atoms: { pagination: paginationAtom }, @@ -330,8 +330,8 @@ Wrong: function MyTable() { const sortingAtom = createAtom([]) // new atom every render useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, atoms: { sorting: sortingAtom }, @@ -345,8 +345,8 @@ Correct: function MyTable() { const sortingAtom = useCreateAtom([]) // stable across renders useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, atoms: { sorting: sortingAtom }, @@ -357,19 +357,19 @@ function MyTable() { A fresh atom each render unbinds the table from the slice and resets the state to the initial value on every render. Source: `examples/preact/basic-external-atoms/src/main.tsx`. -### HIGH Unstable `data` / `columns` / `_features` references +### HIGH Unstable `data` / `columns` / `features` references Wrong: ```tsx function MyTable({ rows }) { - const _features = tableFeatures({ rowSortingFeature }) // new every render + const features = tableFeatures({ rowSortingFeature }) // new every render const columns = [ /* … */ ] // new every render const table = useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data: rows ?? [], }) @@ -380,15 +380,15 @@ Correct: ```tsx // Module scope — declared once. -const _features = tableFeatures({ rowSortingFeature }) -const columns: ColumnDef[] = [ +const features = tableFeatures({ rowSortingFeature }) +const columns: ColumnDef[] = [ /* … */ ] const EMPTY: Person[] = [] function MyTable({ rows }) { const data = rows ?? EMPTY - const table = useTable({ _features, _rowModels: {}, columns, data }) + const table = useTable({ features, rowModels: {}, columns, data }) } ``` @@ -407,17 +407,17 @@ const sorted = useMemo(() => [...data].sort(/* … */), [data, sorting]) Correct: ```tsx -const _features = tableFeatures({ rowSortingFeature }) +const features = tableFeatures({ rowSortingFeature }) const table = useTable({ - _features, - _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, data, }) const rows = table.getRowModel().rows // already sorted ``` -TanStack Table v9 ships built-ins for sorting, filtering, pagination, grouping, expanding, faceting, row selection, column visibility/order/pinning/sizing, and row pinning. Register the matching `*Feature` in `_features`, register its row-model factory in `_rowModels`, and call the feature APIs (`setSorting`, `setColumnFilters`, etc.). Re-implementing these by hand is the #1 AI tell. +TanStack Table v9 ships built-ins for sorting, filtering, pagination, grouping, expanding, faceting, row selection, column visibility/order/pinning/sizing, and row pinning. Register the matching `*Feature` in `features`, register its row-model factory in `rowModels`, and call the feature APIs (`setSorting`, `setColumnFilters`, etc.). Re-implementing these by hand is the #1 AI tell. Source: `docs/guide/features.md`. ## See Also diff --git a/packages/preact-table/skills/preact/table-state/references/advanced-state-patterns.md b/packages/preact-table/skills/preact/table-state/references/advanced-state-patterns.md index 96517cc763..b0ac7dc6ce 100644 --- a/packages/preact-table/skills/preact/table-state/references/advanced-state-patterns.md +++ b/packages/preact-table/skills/preact/table-state/references/advanced-state-patterns.md @@ -14,8 +14,8 @@ const [pagination, setPagination] = useState({ }) const table = useTable({ - _features, - _rowModels: { + features, + rowModels: { /* … */ }, columns, @@ -30,7 +30,7 @@ Source: `docs/framework/preact/guide/table-state.md`. ## `createTableHook` for reusable shared config -When you ship the same `_features` / `_rowModels` / cell components across many tables, package them with `createTableHook`. You get `useAppTable`, `createAppColumnHelper`, `useTableContext` / `useCellContext` / `useHeaderContext`, and `table.AppTable` / `AppHeader` / `AppCell` / `AppFooter` boundaries. +When you ship the same `features` / `rowModels` / cell components across many tables, package them with `createTableHook`. You get `useAppTable`, `createAppColumnHelper`, `useTableContext` / `useCellContext` / `useHeaderContext`, and `table.AppTable` / `AppHeader` / `AppCell` / `AppFooter` boundaries. ```tsx import { @@ -50,8 +50,8 @@ export const { useCellContext, useHeaderContext, } = createTableHook({ - _features: tableFeatures({ rowPaginationFeature, rowSortingFeature }), - _rowModels: { + features: tableFeatures({ rowPaginationFeature, rowSortingFeature }), + rowModels: { paginatedRowModel: createPaginatedRowModel(), sortedRowModel: createSortedRowModel(sortFns), }, diff --git a/packages/preact-table/src/createTableHook.tsx b/packages/preact-table/src/createTableHook.tsx index 71dbd53eff..eb508d0a6d 100644 --- a/packages/preact-table/src/createTableHook.tsx +++ b/packages/preact-table/src/createTableHook.tsx @@ -521,12 +521,12 @@ export type AppPreactTable< * useCellContext, * useHeaderContext, * } = createTableHook({ - * _features: tableFeatures({ + * features: tableFeatures({ * rowPaginationFeature, * rowSortingFeature, * columnFilteringFeature, * }), - * _rowModels: { + * rowModels: { * paginatedRowModel: createPaginatedRowModel(), * sortedRowModel: createSortedRowModel(sortFns), * filteredRowModel: createFilteredRowModel(filterFns), @@ -802,7 +802,7 @@ export function createTableHook< >( tableOptions: Omit< TableOptions, - '_features' | '_rowModels' + 'features' | 'rowModels' >, selector?: (state: TableState) => TSelected, ): AppPreactTable< @@ -1113,7 +1113,7 @@ export function createTableHook< } return { - appFeatures: defaultTableOptions._features as TFeatures, + appFeatures: defaultTableOptions.features as TFeatures, createAppColumnHelper, useAppTable, useTableContext, diff --git a/packages/preact-table/src/useTable.ts b/packages/preact-table/src/useTable.ts index ddaf2919ab..939c783f6a 100644 --- a/packages/preact-table/src/useTable.ts +++ b/packages/preact-table/src/useTable.ts @@ -99,8 +99,8 @@ export type PreactTable< * ```tsx * const table = useTable( * { - * _features, - * _rowModels: {}, + * features, + * rowModels: {}, * columns, * data, * }, @@ -121,9 +121,9 @@ export function useTable< const [table] = useState(() => { const tableInstance = constructTable({ ...tableOptions, - _features: { + features: { coreReativityFeature: preactReactivity(), - ...tableOptions._features, + ...tableOptions.features, }, }) as unknown as PreactTable diff --git a/packages/react-table-devtools/skills/react/compose-with-tanstack-devtools/SKILL.md b/packages/react-table-devtools/skills/react/compose-with-tanstack-devtools/SKILL.md index 7befb58fec..60f807746f 100644 --- a/packages/react-table-devtools/skills/react/compose-with-tanstack-devtools/SKILL.md +++ b/packages/react-table-devtools/skills/react/compose-with-tanstack-devtools/SKILL.md @@ -48,8 +48,8 @@ import { function UsersScreen() { const table = useTable({ - _features, - _rowModels, + features, + rowModels, key: 'users-table', columns, data, diff --git a/packages/react-table/skills/react/client-to-server/SKILL.md b/packages/react-table/skills/react/client-to-server/SKILL.md index 966339da5e..2681788af5 100644 --- a/packages/react-table/skills/react/client-to-server/SKILL.md +++ b/packages/react-table/skills/react/client-to-server/SKILL.md @@ -5,7 +5,7 @@ description: > (manual modes). Pass server-paginated/sorted/filtered rows as `data`, set `manualPagination` / `manualSorting` / `manualFiltering` / `manualGrouping` / `manualExpanding` for whatever the server now owns, supply `rowCount` so - `getPageCount()` works, and DROP the matching `_rowModels` entry (no + `getPageCount()` works, and DROP the matching `rowModels` entry (no `paginatedRowModel` if the server paginates). Own the relevant state slices via external atoms (`useCreateAtom` + `options.atoms`) so a query can key on the slice and refetch automatically — OR via classic `state` + `on*Change` @@ -35,7 +35,7 @@ A client-side table sees every row, sorts/filters/paginates them locally, and re Four moves convert any client table to a server table: 1. **`manualX: true`** for whichever operations the server owns. -2. **Drop the matching factory** from `_rowModels` so it doesn't ship in your bundle. +2. **Drop the matching factory** from `rowModels` so it doesn't ship in your bundle. 3. **Provide `rowCount`** so `table.getPageCount()` / `getCanNextPage()` work. 4. **Own the slice state externally** so your data fetcher can key on it. @@ -56,8 +56,8 @@ import { } from '@tanstack/react-table' import type { PaginationState } from '@tanstack/react-table' -const _features = tableFeatures({ rowPaginationFeature }) -const columnHelper = createColumnHelper() +const features = tableFeatures({ rowPaginationFeature }) +const columnHelper = createColumnHelper() const columns = columnHelper.columns([ columnHelper.accessor('firstName', { header: 'First' }), columnHelper.accessor('age', { header: 'Age' }), @@ -88,10 +88,10 @@ function ServerTable() { } }, [pagination]) - // 3) Manual pagination + rowCount. No paginatedRowModel in _rowModels. + // 3) Manual pagination + rowCount. No paginatedRowModel in rowModels. const table = useTable({ - _features, - _rowModels: {}, // core only — server slices + features, + rowModels: {}, // core only — server slices columns, data: serverPage?.rows ?? EMPTY, // EMPTY at module scope rowCount: serverPage?.rowCount, @@ -113,8 +113,8 @@ const [pagination, setPagination] = React.useState({ }) const table = useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data: serverPage?.rows ?? EMPTY, rowCount: serverPage?.rowCount, @@ -133,7 +133,7 @@ Both work. `state` + `on*Change` is familiar from v8; atoms compose more cleanly Add the matching `manual*` flags for each operation the server now owns. Local features (column visibility, ordering, pinning) still work because they don't depend on the row model. ```tsx -const _features = tableFeatures({ +const features = tableFeatures({ rowSortingFeature, rowPaginationFeature, columnFilteringFeature, @@ -156,8 +156,8 @@ const serverArgs = { sorting, pagination, columnFilters } // ... fetch keyed on serverArgs const table = useTable({ - _features, - _rowModels: {}, // no sorted/filtered/paginated factories — server owns them + features, + rowModels: {}, // no sorted/filtered/paginated factories — server owns them columns, data: serverPage?.rows ?? EMPTY, rowCount: serverPage?.rowCount, @@ -186,8 +186,8 @@ Wrong: ```tsx const table = useTable({ - _features, - _rowModels: { paginatedRowModel: createPaginatedRowModel() }, + features, + rowModels: { paginatedRowModel: createPaginatedRowModel() }, columns, data: serverPage.rows, // missing manualPagination @@ -198,8 +198,8 @@ Correct: ```tsx const table = useTable({ - _features, - _rowModels: {}, // dropped — server paginates + features, + rowModels: {}, // dropped — server paginates columns, data: serverPage.rows, rowCount: serverPage.rowCount, @@ -216,8 +216,8 @@ Wrong: ```tsx const table = useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data: serverPage.rows, manualPagination: true, @@ -230,8 +230,8 @@ Correct: ```tsx const table = useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data: serverPage.rows, rowCount: serverPage.rowCount, // ← required for accurate pager @@ -252,8 +252,8 @@ const [pagination] = React.useState({ pageSize: 10, }) useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, state: { pagination }, @@ -270,8 +270,8 @@ const [pagination, setPagination] = React.useState({ pageSize: 10, }) useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, state: { pagination }, @@ -290,8 +290,8 @@ Wrong: ```tsx useTable({ - _features, - _rowModels: { paginatedRowModel: createPaginatedRowModel() }, // ships for nothing + features, + rowModels: { paginatedRowModel: createPaginatedRowModel() }, // ships for nothing columns, data: serverPage.rows, manualPagination: true, @@ -302,8 +302,8 @@ Correct: ```tsx useTable({ - _features, - _rowModels: {}, // drop it — server owns pagination + features, + rowModels: {}, // drop it — server owns pagination columns, data: serverPage.rows, rowCount: serverPage.rowCount, @@ -320,8 +320,8 @@ Wrong: ```tsx useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, state: { pagination }, // silently ignored @@ -336,8 +336,8 @@ Correct: ```tsx // Pick one ownership mechanism per slice. useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, atoms: { pagination: paginationAtom }, diff --git a/packages/react-table/skills/react/compose-with-tanstack-form/SKILL.md b/packages/react-table/skills/react/compose-with-tanstack-form/SKILL.md index 4d3f4e0987..cde709bf7d 100644 --- a/packages/react-table/skills/react/compose-with-tanstack-form/SKILL.md +++ b/packages/react-table/skills/react/compose-with-tanstack-form/SKILL.md @@ -89,11 +89,11 @@ import type { Person } from './makeData' // Without Omit, TanStack Form's DeepKeys walks subRows and hits TS2589. type FormRow = Omit -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, columnFilteringFeature, }) -const columnHelper = createColumnHelper() +const columnHelper = createColumnHelper() function App() { const initialData: FormRow[] = makeData(100) @@ -151,8 +151,8 @@ function App() { void dataLength const table = useTable({ - _features, - _rowModels: { + features, + rowModels: { filteredRowModel: createFilteredRowModel(filterFns), paginatedRowModel: createPaginatedRowModel(), }, @@ -220,7 +220,7 @@ Correct: type FormRow = Omit const initialData: FormRow[] = makeData(100) const form = useAppForm({ defaultValues: { data: initialData } }) -const columnHelper = createColumnHelper() +const columnHelper = createColumnHelper() ``` Always strip the recursive child field from the row type you hand to the form. @@ -295,8 +295,8 @@ Wrong: ```tsx const table = useTable({ - _features, - _rowModels: { + features, + rowModels: { /* … */ }, columns, @@ -308,8 +308,8 @@ Correct: ```tsx const table = useTable({ - _features, - _rowModels: { + features, + rowModels: { /* … */ }, columns, @@ -343,8 +343,8 @@ Correct: // v9 idiom: TanStack Form owns the data, table renders it. const form = useAppForm({ defaultValues: { data } }) const table = useTable({ - _features, - _rowModels: { + features, + rowModels: { /* … */ }, columns, diff --git a/packages/react-table/skills/react/compose-with-tanstack-query/SKILL.md b/packages/react-table/skills/react/compose-with-tanstack-query/SKILL.md index 5f1c3ea195..fdc1f82c5d 100644 --- a/packages/react-table/skills/react/compose-with-tanstack-query/SKILL.md +++ b/packages/react-table/skills/react/compose-with-tanstack-query/SKILL.md @@ -71,9 +71,9 @@ import type { PaginationState } from '@tanstack/react-table' import { fetchData } from './fetchData' // returns { rows, rowCount } import type { Person } from './fetchData' -const _features = tableFeatures({ rowPaginationFeature }) +const features = tableFeatures({ rowPaginationFeature }) -const columnHelper = createColumnHelper() +const columnHelper = createColumnHelper() const columns = columnHelper.columns([ columnHelper.accessor('firstName', { header: 'First Name', @@ -111,8 +111,8 @@ function App() { // 6) Manual pagination + rowCount; no paginatedRowModel. const table = useTable( { - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data: dataQuery.data?.rows ?? defaultData, rowCount: dataQuery.data?.rowCount, @@ -180,7 +180,7 @@ Source: `examples/react/with-tanstack-query/src/main.tsx` (this is the canonical ## Adding sort + filter -The same pattern extends to multiple slices. Key the query on each, set the matching `manual*` flag, drop the matching `_rowModels` factory. +The same pattern extends to multiple slices. Key the query on each, set the matching `manual*` flag, drop the matching `rowModels` factory. ```tsx const paginationAtom = useCreateAtom({ @@ -201,12 +201,12 @@ const dataQuery = useQuery({ }) const table = useTable({ - _features: tableFeatures({ + features: tableFeatures({ rowPaginationFeature, rowSortingFeature, columnFilteringFeature, }), - _rowModels: {}, // server owns sort/filter/paginate + rowModels: {}, // server owns sort/filter/paginate columns, data: dataQuery.data?.rows ?? defaultData, rowCount: dataQuery.data?.rowCount, @@ -241,8 +241,8 @@ Wrong: ```tsx const table = useTable({ - _features, - _rowModels: { paginatedRowModel: createPaginatedRowModel() }, + features, + rowModels: { paginatedRowModel: createPaginatedRowModel() }, columns, data: query.data?.rows ?? [], // missing manualPagination @@ -253,8 +253,8 @@ Correct: ```tsx const table = useTable({ - _features, - _rowModels: {}, // drop paginatedRowModel + features, + rowModels: {}, // drop paginatedRowModel columns, data: query.data?.rows ?? defaultData, rowCount: query.data?.rowCount, @@ -272,8 +272,8 @@ Wrong: ```tsx const table = useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data: query.data?.rows ?? defaultData, atoms: { pagination: paginationAtom }, @@ -286,8 +286,8 @@ Correct: ```tsx const table = useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data: query.data?.rows ?? defaultData, rowCount: query.data?.rowCount, // ← required for accurate pager @@ -354,8 +354,8 @@ Wrong: ```tsx const table = useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data: query.data?.rows ?? [], // new identity every render // ... @@ -369,8 +369,8 @@ const defaultData = React.useMemo(() => [], []) // or: const EMPTY: Person[] = [] at module scope const table = useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data: query.data?.rows ?? defaultData, // ... @@ -386,8 +386,8 @@ Wrong: ```tsx useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, state: { pagination }, // silently ignored @@ -402,8 +402,8 @@ Correct: ```tsx // Pick one. The atom pattern is canonical for Query. useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, atoms: { pagination: paginationAtom }, @@ -444,7 +444,7 @@ Source: docs/framework/react/react-query. Wrong: ```tsx -_rowModels: { +rowModels: { paginatedRowModel: createPaginatedRowModel() } // ships unused code ``` @@ -452,7 +452,7 @@ _rowModels: { Correct: ```tsx -_rowModels: { +rowModels: { } // server paginates; drop the factory ``` diff --git a/packages/react-table/skills/react/compose-with-tanstack-store/SKILL.md b/packages/react-table/skills/react/compose-with-tanstack-store/SKILL.md index 924c7e4284..c4563509c1 100644 --- a/packages/react-table/skills/react/compose-with-tanstack-store/SKILL.md +++ b/packages/react-table/skills/react/compose-with-tanstack-store/SKILL.md @@ -71,7 +71,7 @@ import { } from '@tanstack/react-table' import type { PaginationState, SortingState } from '@tanstack/react-table' -const _features = tableFeatures({ rowSortingFeature, rowPaginationFeature }) +const features = tableFeatures({ rowSortingFeature, rowPaginationFeature }) function MyTable({ columns, data }) { const sortingAtom = useCreateAtom([]) @@ -85,8 +85,8 @@ function MyTable({ columns, data }) { const pagination = useSelector(paginationAtom) const table = useTable({ - _features, - _rowModels: { + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns), paginatedRowModel: createPaginatedRowModel(), }, @@ -134,8 +134,8 @@ React.useEffect(() => { }, [visibilityAtom]) const table = useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, atoms: { columnVisibility: visibilityAtom }, @@ -160,8 +160,8 @@ function OrdersTable() { function Table({ data, filter }) { const table = useTable({ - _features, - _rowModels: { + features, + rowModels: { /* … */ }, columns, @@ -199,8 +199,8 @@ Wrong: function MyTable() { const sortingAtom = createAtom([]) // new atom every render useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, atoms: { sorting: sortingAtom }, @@ -214,8 +214,8 @@ Correct: function MyTable() { const sortingAtom = useCreateAtom([]) // stable across renders useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, atoms: { sorting: sortingAtom }, @@ -232,8 +232,8 @@ Wrong: ```tsx useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, state: { sorting: localSorting }, // silently ignored @@ -247,8 +247,8 @@ Correct: ```tsx // Pick exactly one ownership mechanism per slice. useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, atoms: { sorting: sortingAtom }, @@ -264,8 +264,8 @@ Wrong: ```tsx useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, atoms: { sorting: sortingAtom }, @@ -277,8 +277,8 @@ Correct: ```tsx useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, atoms: { sorting: sortingAtom }, diff --git a/packages/react-table/skills/react/compose-with-tanstack-virtual/SKILL.md b/packages/react-table/skills/react/compose-with-tanstack-virtual/SKILL.md index 506edb4bf8..2b70af5707 100644 --- a/packages/react-table/skills/react/compose-with-tanstack-virtual/SKILL.md +++ b/packages/react-table/skills/react/compose-with-tanstack-virtual/SKILL.md @@ -83,8 +83,8 @@ function App() { const [data] = React.useState(() => makeData(200_000)) const table = useTable({ - _features: features, - _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features: features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, data, }) diff --git a/packages/react-table/skills/react/compose-with-tanstack-virtual/references/column-virtualization-and-infinite-scroll.md b/packages/react-table/skills/react/compose-with-tanstack-virtual/references/column-virtualization-and-infinite-scroll.md index a957867541..044a21a55f 100644 --- a/packages/react-table/skills/react/compose-with-tanstack-virtual/references/column-virtualization-and-infinite-scroll.md +++ b/packages/react-table/skills/react/compose-with-tanstack-virtual/references/column-virtualization-and-infinite-scroll.md @@ -50,8 +50,8 @@ const flatRows = React.useMemo( ) const table = useTable({ - _features: tableFeatures({ rowSortingFeature }), - _rowModels: {}, // server sorts each page + features: tableFeatures({ rowSortingFeature }), + rowModels: {}, // server sorts each page columns, data: flatRows, manualSorting: true, @@ -114,8 +114,8 @@ Wrong: ```tsx const table = useTable({ - _features: tableFeatures({ rowSortingFeature }), - _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features: tableFeatures({ rowSortingFeature }), + rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, data: flatRows, }) // Each new page arrives → table re-sorts everything → row order scrambles between pages. @@ -125,8 +125,8 @@ Correct: ```tsx const table = useTable({ - _features: tableFeatures({ rowSortingFeature }), - _rowModels: {}, // server sorts each page + features: tableFeatures({ rowSortingFeature }), + rowModels: {}, // server sorts each page data: flatRows, manualSorting: true, }) diff --git a/packages/react-table/skills/react/getting-started/SKILL.md b/packages/react-table/skills/react/getting-started/SKILL.md index 8962b2b4b2..2b9f83cd65 100644 --- a/packages/react-table/skills/react/getting-started/SKILL.md +++ b/packages/react-table/skills/react/getting-started/SKILL.md @@ -2,7 +2,7 @@ name: react/getting-started description: > End-to-end first-table journey for `@tanstack/react-table` v9. Install the - React adapter, declare `_features` via `tableFeatures()`, declare `_rowModels` + React adapter, declare `features` via `tableFeatures()`, declare `rowModels` factories with their *Fns parameters (`createSortedRowModel(sortFns)` etc.), create a column helper with both `TFeatures` and `TData` generics, instantiate `useTable`, and render with ``. New users land here, not on @@ -23,7 +23,7 @@ sources: - TanStack/table:examples/react/basic-use-app-table/src/main.tsx --- -This skill builds on `tanstack-table/state-management` and `tanstack-table/react/table-state`. Read those first — `_features` + `_rowModels` come from the core state-management concept, and `table-state` covers how reactivity flows in React. +This skill builds on `tanstack-table/state-management` and `tanstack-table/react/table-state`. Read those first — `features` + `rowModels` come from the core state-management concept, and `table-state` covers how reactivity flows in React. ## Install @@ -39,9 +39,9 @@ npm install @tanstack/react-table Three things are non-negotiable, even for the simplest possible table: -1. `_features: tableFeatures({...})` — required even if empty (`tableFeatures({})`). -2. `_rowModels: {...}` — required even if empty (`_rowModels: {}`). The **core** row model is automatic; you only register sorted/filtered/paginated/grouped/etc. when you use them. -3. `createColumnHelper()` — generic order is `` in v9 (changed from v8). +1. `features: tableFeatures({...})` — required even if empty (`tableFeatures({})`). +2. `rowModels: {...}` — required even if empty (`rowModels: {}`). The **core** row model is automatic; you only register sorted/filtered/paginated/grouped/etc. when you use them. +3. `createColumnHelper()` — generic order is `` in v9 (changed from v8). ```tsx import * as React from 'react' @@ -57,11 +57,11 @@ type Person = { progress: number } -// 1. _features — required option, even if empty. -const _features = tableFeatures({}) +// 1. features — required option, even if empty. +const features = tableFeatures({}) // 2. Columns — defined at module scope for stable identity. -const columns: Array> = [ +const columns: Array> = [ { accessorKey: 'firstName', header: 'First Name', @@ -77,11 +77,11 @@ const columns: Array> = [ function App({ initialData }: { initialData: Person[] }) { const [data] = React.useState(() => initialData) - // 3. Build the table — `_rowModels: {}` is required. + // 3. Build the table — `rowModels: {}` is required. const table = useTable( { - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, }, @@ -121,7 +121,7 @@ Source: `examples/react/basic-use-table/src/main.tsx`. ## Adding sorting -Register the feature in `_features`, the factory in `_rowModels`, and wire a click handler: +Register the feature in `features`, the factory in `rowModels`, and wire a click handler: ```tsx import { @@ -133,8 +133,8 @@ import { createColumnHelper, } from '@tanstack/react-table' -const _features = tableFeatures({ rowSortingFeature }) -const columnHelper = createColumnHelper() +const features = tableFeatures({ rowSortingFeature }) +const columnHelper = createColumnHelper() const columns = columnHelper.columns([ columnHelper.accessor('firstName', { header: 'First' }), @@ -143,8 +143,8 @@ const columns = columnHelper.columns([ function App({ data }: { data: Person[] }) { const table = useTable({ - _features, - _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, data, }) @@ -178,15 +178,15 @@ function App({ data }: { data: Person[] }) { Adding pagination and filtering is purely additive — register the feature + factory, and call the built-in APIs: ```tsx -const _features = tableFeatures({ +const features = tableFeatures({ rowSortingFeature, rowPaginationFeature, columnFilteringFeature, }) const table = useTable({ - _features, - _rowModels: { + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns), filteredRowModel: createFilteredRowModel(filterFns), paginatedRowModel: createPaginatedRowModel(), @@ -207,14 +207,14 @@ Source: `docs/framework/react/react-table.md`; `examples/react/basic-use-table/s ## Optional: `createTableHook` for shared config -If you ship the same `_features` / `_rowModels` / cell components across many tables, package them once: +If you ship the same `features` / `rowModels` / cell components across many tables, package them once: ```tsx import { createTableHook } from '@tanstack/react-table' const { useAppTable, createAppColumnHelper } = createTableHook({ - _features: {}, - _rowModels: {}, + features: {}, + rowModels: {}, debugTable: true, }) @@ -233,24 +233,24 @@ Source: `examples/react/basic-use-app-table/src/main.tsx`. ## Common Mistakes -### CRITICAL Forgetting `_features: tableFeatures({})` +### CRITICAL Forgetting `features: tableFeatures({})` Wrong: ```tsx const table = useTable({ - _rowModels: {}, + rowModels: {}, columns, data, }) -// TS: Property '_features' is missing in type +// TS: Property 'features' is missing in type ``` Correct: ```tsx -const _features = tableFeatures({}) -const table = useTable({ _features, _rowModels: {}, columns, data }) +const features = tableFeatures({}) +const table = useTable({ features, rowModels: {}, columns, data }) ``` The option is required even for a "no features" table — pass `tableFeatures({})` or `stockFeatures` if you want v8-style "everything on". @@ -274,8 +274,8 @@ Correct: ```tsx const table = useTable({ - _features: tableFeatures({ rowSortingFeature }), - _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features: tableFeatures({ rowSortingFeature }), + rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, data, }) @@ -285,30 +285,30 @@ const table = useTable({ Maintainer flags this as the #1 tell that "an AI wrote this." The built-ins handle reset semantics, multi-sort, internal invariants. Source: maintainer interview (Phase 4). -### CRITICAL API "missing" because the feature was not registered in `_features` +### CRITICAL API "missing" because the feature was not registered in `features` Wrong: ```tsx -const _features = tableFeatures({}) // empty -const table = useTable({ _features, _rowModels: {}, columns, data }) +const features = tableFeatures({}) // empty +const table = useTable({ features, rowModels: {}, columns, data }) table.setSorting([{ id: 'age', desc: true }]) // TS error — does not exist on this table type ``` Correct: ```tsx -const _features = tableFeatures({ rowSortingFeature }) +const features = tableFeatures({ rowSortingFeature }) const table = useTable({ - _features, - _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, data, }) table.setSorting([{ id: 'age', desc: true }]) // ✓ ``` -In v9, `_features` is a tree-shakeable registry. If a feature isn't listed, TypeScript hides its APIs and the runtime atom is never created — the feature isn't broken, it's just not on. +In v9, `features` is a tree-shakeable registry. If a feature isn't listed, TypeScript hides its APIs and the runtime atom is never created — the feature isn't broken, it's just not on. Source: maintainer interview (Phase 4); `docs/framework/react/react-table.md`. ### HIGH Wrong generic order on `createColumnHelper` @@ -322,22 +322,22 @@ const columnHelper = createColumnHelper() // v8 arity Correct: ```tsx -const _features = tableFeatures({ +const features = tableFeatures({ /* … */ }) -const columnHelper = createColumnHelper() // v9: +const columnHelper = createColumnHelper() // v9: ``` -v9 added `TFeatures` as the first generic across `Column`, `Row`, `ColumnDef`, `ColumnMeta`, etc. Use `typeof _features` so the same feature set drives types and runtime. +v9 added `TFeatures` as the first generic across `Column`, `Row`, `ColumnDef`, `ColumnMeta`, etc. Use `typeof features` so the same feature set drives types and runtime. Source: `docs/framework/react/react-table.md`. -### HIGH Defining `_features` / `columns` / `data` inside the render body +### HIGH Defining `features` / `columns` / `data` inside the render body Wrong: ```tsx function MyTable({ rows }) { - const _features = tableFeatures({ rowSortingFeature }) // new every render + const features = tableFeatures({ rowSortingFeature }) // new every render const columns = [/* … */] // new every render return
`, etc. remains the same. -The main change is **how you define a table** with the `useTable` hook — specifically the new `_features` and `_rowModels` options. +The main change is **how you define a table** with the `useTable` hook — specifically the new `features` and `rowModels` options. --- @@ -75,7 +75,7 @@ import { useTable } from '@tanstack/react-table' const table = useTable(options) ``` -### New Required Options: `_features` and `_rowModels` +### New Required Options: `features` and `rowModels` In v9, you must explicitly declare which features and row models your table uses: @@ -92,11 +92,11 @@ const table = useReactTable({ // v9 import { useTable, tableFeatures } from '@tanstack/react-table' -const _features = tableFeatures({}) // Empty = core features only +const features = tableFeatures({}) // Empty = core features only const table = useTable({ - _features, - _rowModels: {}, // Core row model is automatic + features, + rowModels: {}, // Core row model is automatic columns, data, }) @@ -104,7 +104,7 @@ const table = useTable({ --- -## The `_features` Option +## The `features` Option Features control what table functionality is available. In v8, all features were bundled. In v9, you import only what you need. @@ -122,7 +122,7 @@ import { } from '@tanstack/react-table' // Create a features object (define this outside your component for stable reference) -const _features = tableFeatures({ +const features = tableFeatures({ columnFilteringFeature, rowSortingFeature, rowPaginationFeature, @@ -139,8 +139,8 @@ If you want all features without thinking about it (like v8), import `stockFeatu import { useTable, stockFeatures } from '@tanstack/react-table' const table = useTable({ - _features: stockFeatures, // All features included - _rowModels: { /* ... */ }, + features: stockFeatures, // All features included + rowModels: { /* ... */ }, columns, data, }) @@ -167,13 +167,13 @@ const table = useTable({ --- -## The `_rowModels` Option +## The `rowModels` Option -Row models are the functions that process your data (filtering, sorting, pagination, etc.). In v9, they're configured via `_rowModels` instead of `get*RowModel` options. +Row models are the functions that process your data (filtering, sorting, pagination, etc.). In v9, they're configured via `rowModels` instead of `get*RowModel` options. ### Migration Mapping -| v8 Option | v9 `_rowModels` Key | v9 Factory Function | +| v8 Option | v9 `rowModels` Key | v9 Factory Function | |-----------|---------------------|---------------------| | `getCoreRowModel()` | (automatic) | Not needed — always included | | `getFilteredRowModel()` | `filteredRowModel` | `createFilteredRowModel(filterFns)` | @@ -200,8 +200,8 @@ import { } from '@tanstack/react-table' const table = useTable({ - _features, - _rowModels: { + features, + rowModels: { filteredRowModel: createFilteredRowModel(filterFns), sortedRowModel: createSortedRowModel(sortFns), groupedRowModel: createGroupedRowModel(aggregationFns), @@ -251,15 +251,15 @@ import { sortFns, } from '@tanstack/react-table' -const _features = tableFeatures({ +const features = tableFeatures({ columnFilteringFeature, rowSortingFeature, rowPaginationFeature, }) const table = useTable({ - _features, - _rowModels: { + features, + rowModels: { filteredRowModel: createFilteredRowModel(filterFns), // now called "create*RowModel()" with a Fns parameter sortedRowModel: createSortedRowModel(sortFns), paginatedRowModel: createPaginatedRowModel(), @@ -320,8 +320,8 @@ The biggest state management improvement is `table.Subscribe`, which enables fin ```tsx function MyTable() { const table = useTable({ - _features, - _rowModels: { /* ... */ }, + features, + rowModels: { /* ... */ }, columns, data, }) @@ -353,8 +353,8 @@ If you want v8-style behavior where the component re-renders on any state change // Re-renders on ANY state change (like v8) const table = useTable( { - _features, - _rowModels: { /* ... */ }, + features, + rowModels: { /* ... */ }, columns, data, }, @@ -377,8 +377,8 @@ const [pagination, setPagination] = useState({ }) const table = useTable({ - _features, - _rowModels: { /* ... */ }, + features, + rowModels: { /* ... */ }, columns, data, state: { @@ -426,7 +426,7 @@ import { } from '@tanstack/react-table' import type { PaginationState, SortingState } from '@tanstack/react-table' -const _features = tableFeatures({ rowSortingFeature, rowPaginationFeature }) +const features = tableFeatures({ rowSortingFeature, rowPaginationFeature }) function MyTable({ data, columns }) { // Create stable external atoms for the slices you want to own. @@ -441,8 +441,8 @@ function MyTable({ data, columns }) { const pagination = useSelector(paginationAtom) const table = useTable({ - _features, - _rowModels: { + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns), paginatedRowModel: createPaginatedRowModel(), }, @@ -494,8 +494,8 @@ const columnHelper = createColumnHelper() // v9 import { createColumnHelper, tableFeatures, rowSortingFeature } from '@tanstack/react-table' -const _features = tableFeatures({ rowSortingFeature }) -const columnHelper = createColumnHelper() +const features = tableFeatures({ rowSortingFeature }) +const columnHelper = createColumnHelper() ``` ### New `columns()` Helper Method @@ -503,7 +503,7 @@ const columnHelper = createColumnHelper() v9 adds a `columns()` helper for better type inference when wrapping column arrays. In v8, `TValue` wasn't always type-safe—especially with group columns, where nested column types could be lost or widened. The `columns()` helper uses variadic tuple types to preserve each column's individual `TValue` type, so `info.getValue()` and cell renderers stay correctly typed throughout nested structures: ```tsx -const columnHelper = createColumnHelper() +const columnHelper = createColumnHelper() // Wrap your columns array for better type inference const columns = columnHelper.columns([ @@ -530,8 +530,8 @@ When using `createTableHook`, you get a pre-bound `createAppColumnHelper` that o ```tsx const { useAppTable, createAppColumnHelper } = createTableHook({ - _features: tableFeatures({ rowSortingFeature }), - _rowModels: { /* ... */ }, + features: tableFeatures({ rowSortingFeature }), + rowModels: { /* ... */ }, }) // TFeatures is already bound — only need TData! @@ -597,7 +597,7 @@ import { tableOptions, tableFeatures, rowSortingFeature } from '@tanstack/react- // Create a reusable options object with features pre-configured const baseOptions = tableOptions({ - _features: tableFeatures({ rowSortingFeature }), + features: tableFeatures({ rowSortingFeature }), debugTable: process.env.NODE_ENV === 'development', }) @@ -606,30 +606,30 @@ const table = useTable({ ...baseOptions, columns, data, - _rowModels: {}, + rowModels: {}, }) ``` ### Composing Partial Options -`tableOptions()` allows you to omit certain required fields (like `data`, `columns`, or `_features`) when creating partial configurations: +`tableOptions()` allows you to omit certain required fields (like `data`, `columns`, or `features`) when creating partial configurations: ```tsx // Partial options without data or columns const featureOptions = tableOptions({ - _features: tableFeatures({ + features: tableFeatures({ rowSortingFeature, columnFilteringFeature, }), - _rowModels: { + rowModels: { sortedRowModel: createSortedRowModel(sortFns), filteredRowModel: createFilteredRowModel(filterFns), }, }) -// Another partial without _features (inherits from spread) +// Another partial without features (inherits from spread) const paginationDefaults = tableOptions({ - _rowModels: { + rowModels: { paginatedRowModel: createPaginatedRowModel(), }, initialState: { @@ -652,8 +652,8 @@ const table = useTable({ ```tsx const sharedOptions = tableOptions({ - _features: tableFeatures({ rowSortingFeature, rowPaginationFeature }), - _rowModels: { + features: tableFeatures({ rowSortingFeature, rowPaginationFeature }), + rowModels: { sortedRowModel: createSortedRowModel(sortFns), paginatedRowModel: createPaginatedRowModel(), }, @@ -696,14 +696,14 @@ export const { useHeaderContext, } = createTableHook({ // Features defined once - _features: tableFeatures({ + features: tableFeatures({ columnFilteringFeature, rowSortingFeature, rowPaginationFeature, }), // Row models defined once - _rowModels: { + rowModels: { filteredRowModel: createFilteredRowModel(filterFns), sortedRowModel: createSortedRowModel(sortFns), paginatedRowModel: createPaginatedRowModel(), @@ -738,7 +738,7 @@ function UsersTable({ data }: { data: Person[] }) { const table = useAppTable({ columns, data, - // _features and _rowModels already configured! + // features and rowModels already configured! }) return ( @@ -868,7 +868,7 @@ If you only need column sizing (fixed widths) without interactive resizing, you ```tsx import { columnSizingFeature, columnResizingFeature } from '@tanstack/react-table' -const _features = tableFeatures({ +const features = tableFeatures({ columnSizingFeature, columnResizingFeature, // Only if you need interactive resizing }) @@ -941,22 +941,22 @@ type Row type Cell ``` -### Using `typeof _features` +### Using `typeof features` The easiest way to get the `TFeatures` type is with `typeof`: ```tsx -const _features = tableFeatures({ +const features = tableFeatures({ rowSortingFeature, columnFilteringFeature, }) // Use typeof to get the type -type MyFeatures = typeof _features +type MyFeatures = typeof features -const columns: ColumnDef[] = [...] +const columns: ColumnDef[] = [...] -function Filter({ column }: { column: Column }) { +function Filter({ column }: { column: Column }) { // ... } ``` @@ -1010,8 +1010,8 @@ This change improves type safety. If you were passing unusual data types, ensure ## Migration Checklist - [ ] Update import: `useReactTable` → `useTable` -- [ ] Define `_features` using `tableFeatures()` (or use `stockFeatures`) -- [ ] Migrate `get*RowModel()` options to `_rowModels` +- [ ] Define `features` using `tableFeatures()` (or use `stockFeatures`) +- [ ] Migrate `get*RowModel()` options to `rowModels` - [ ] Update row model factories to include `Fns` parameters where needed - [ ] Update TypeScript types to include `TFeatures` generic - [ ] Update state access: `table.getState()` → `table.store.state` or `table.state` diff --git a/docs/framework/react/guide/table-state.md b/docs/framework/react/guide/table-state.md index 8c43366a27..72f4d693bc 100644 --- a/docs/framework/react/guide/table-state.md +++ b/docs/framework/react/guide/table-state.md @@ -39,19 +39,19 @@ The important change from previous versions is that table state is now atomic. R ### Feature-based State -State slices are only created for the features that are registered in `_features`. This keeps TanStack Table tree-shakeable and gives TypeScript more accurate state inference. +State slices are only created for the features that are registered in `features`. This keeps TanStack Table tree-shakeable and gives TypeScript more accurate state inference. -For example, if `_features` includes `rowPaginationFeature`, TypeScript exposes pagination state APIs and `table.atoms.pagination`. If `_features` does not include `rowPaginationFeature`, `pagination` should not be available in `table.atoms`, `table.store.state`, `table.state`, `initialState`, `state`, or `atoms`. +For example, if `features` includes `rowPaginationFeature`, TypeScript exposes pagination state APIs and `table.atoms.pagination`. If `features` does not include `rowPaginationFeature`, `pagination` should not be available in `table.atoms`, `table.store.state`, `table.state`, `initialState`, `state`, or `atoms`. ```tsx -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, rowSortingFeature, }) const table = useTable({ - _features, - _rowModels: { + features, + rowModels: { paginatedRowModel: createPaginatedRowModel(), sortedRowModel: createSortedRowModel(sortFns), }, @@ -103,8 +103,8 @@ You can pass your own selector to make `table.state` contain only the reactive s ```tsx const table = useTable( { - _features, - _rowModels: { + features, + rowModels: { paginatedRowModel: createPaginatedRowModel(), }, columns, @@ -123,8 +123,8 @@ For large tables, you can also opt the parent table component out of table-state ```tsx const table = useTable( { - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, }, @@ -143,8 +143,8 @@ Without a `source` prop, `table.Subscribe` subscribes to `table.store` and requi ```tsx const table = useTable( { - _features, - _rowModels: { + features, + rowModels: { filteredRowModel: createFilteredRowModel(filterFns), paginatedRowModel: createPaginatedRowModel(), }, @@ -290,8 +290,8 @@ If you only need to customize the starting value for some table state, use `init ```tsx const table = useTable({ - _features, - _rowModels: { + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns), paginatedRowModel: createPaginatedRowModel(), }, @@ -345,7 +345,7 @@ import { type PaginationState, } from '@tanstack/react-table' -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, }) @@ -363,8 +363,8 @@ function App() { }) const table = useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data: dataQuery.data?.rows ?? [], rowCount: dataQuery.data?.rowCount, @@ -394,8 +394,8 @@ const [pagination, setPagination] = React.useState({ }) const table = useTable({ - _features, - _rowModels: { + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns), paginatedRowModel: createPaginatedRowModel(), }, @@ -422,8 +422,8 @@ If you provide an `on[State]Change` callback, also provide the corresponding val const [sorting, setSorting] = React.useState([]) const table = useTable({ - _features, - _rowModels: { + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns), }, columns, @@ -444,8 +444,8 @@ const [pagination, setPagination] = React.useState({ }) const table = useTable({ - _features, - _rowModels: { + features, + rowModels: { paginatedRowModel: createPaginatedRowModel(), }, columns, @@ -486,15 +486,15 @@ const [sorting, setSorting] = React.useState([ ]) ``` -`TableState` is inferred from the features registered on that table: +`TableState` is inferred from the features registered on that table: ```tsx -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, rowSortingFeature, }) -type MyTableState = TableState +type MyTableState = TableState ``` Prefer feature-specific state types like `SortingState`, `PaginationState`, or `RowSelectionState` when you are creating local state or external atoms for one slice. diff --git a/docs/framework/react/guide/use-legacy-table.md b/docs/framework/react/guide/use-legacy-table.md index ce5dd0ef96..af7f5453bc 100644 --- a/docs/framework/react/guide/use-legacy-table.md +++ b/docs/framework/react/guide/use-legacy-table.md @@ -215,8 +215,8 @@ The fine-grained reactivity feature (`table.Subscribe`) is not available with `u Once you're ready to migrate to the full v9 API: 1. Replace `useLegacyTable` with `useTable` -2. Define your `_features` using `tableFeatures()` -3. Convert `get*RowModel()` options to `_rowModels` +2. Define your `features` using `tableFeatures()` +3. Convert `get*RowModel()` options to `rowModels` 4. Update types from `Legacy*` to the standard v9 types See the [main migration guide](./migrating.md) for complete instructions. diff --git a/docs/framework/react/react-table.md b/docs/framework/react/react-table.md index 92a553d872..e8ab0738ea 100644 --- a/docs/framework/react/react-table.md +++ b/docs/framework/react/react-table.md @@ -4,7 +4,7 @@ title: React Table The `@tanstack/react-table` adapter wraps `@tanstack/table-core` with React-specific reactivity, rendering helpers, and types. It installs the React `coreReativityFeature` for you, so table state is backed by TanStack Store atoms while React components can subscribe through `useTable`, selectors, and `table.Subscribe`. -TanStack Table v9 is explicit about what a table uses. Register features with `_features`, and register client-side row model factories with `_rowModels`. The core row model is included by default, so a basic table can use `_rowModels: {}`. +TanStack Table v9 is explicit about what a table uses. Register features with `features`, and register client-side row model factories with `rowModels`. The core row model is included by default, so a basic table can use `rowModels: {}`. ## Creating a Table @@ -19,9 +19,9 @@ type Person = { age: number } -const _features = tableFeatures({}) +const features = tableFeatures({}) -const columns: Array> = [ +const columns: Array> = [ { accessorKey: 'firstName', header: 'First name', @@ -31,8 +31,8 @@ const columns: Array> = [ function App({ data }: { data: Person[] }) { const table = useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, }) @@ -41,7 +41,7 @@ function App({ data }: { data: Person[] }) { } ``` -For feature-specific row models, register the feature and put the row model factory under `_rowModels`. +For feature-specific row models, register the feature and put the row model factory under `rowModels`. ```tsx import { @@ -53,14 +53,14 @@ import { tableFeatures, } from '@tanstack/react-table' -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, rowSortingFeature, }) const tableOptions = { - _features, - _rowModels: { + features, + rowModels: { paginatedRowModel: createPaginatedRowModel(), sortedRowModel: createSortedRowModel(sortFns), }, @@ -82,7 +82,7 @@ import { type PaginationState, } from '@tanstack/react-table' -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, }) @@ -93,8 +93,8 @@ function App({ data }: { data: Person[] }) { }) const table = useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, atoms: { @@ -128,14 +128,14 @@ Use `table.FlexRender` to render column `header`, `cell`, and `footer` definitio ## createTableHook -`createTableHook` creates an app-specific table hook. Use it when multiple tables should share `_features`, `_rowModels`, default options, column helpers, and component conventions. +`createTableHook` creates an app-specific table hook. Use it when multiple tables should share `features`, `rowModels`, default options, column helpers, and component conventions. ```tsx import { createTableHook, tableFeatures } from '@tanstack/react-table' const { useAppTable, createAppColumnHelper } = createTableHook({ - _features: tableFeatures({}), - _rowModels: {}, + features: tableFeatures({}), + rowModels: {}, }) const columnHelper = createAppColumnHelper() diff --git a/docs/framework/react/reference/index/functions/createTableHook.md b/docs/framework/react/reference/index/functions/createTableHook.md index 90220cfbb7..0dfc0ee4f6 100644 --- a/docs/framework/react/reference/index/functions/createTableHook.md +++ b/docs/framework/react/reference/index/functions/createTableHook.md @@ -116,7 +116,7 @@ TFeatures is already known from the createTableHook call; TData is inferred from ##### tableOptions -`Omit`\<`TableOptions`\<`TFeatures`, `TData`\>, `"_features"` \| `"_rowModels"`\> +`Omit`\<`TableOptions`\<`TFeatures`, `TData`\>, `"features"` \| `"rowModels"`\> ##### selector? @@ -252,12 +252,12 @@ export const { useCellContext, useHeaderContext, } = createTableHook({ - _features: tableFeatures({ + features: tableFeatures({ rowPaginationFeature, rowSortingFeature, columnFilteringFeature, }), - _rowModels: { + rowModels: { paginatedRowModel: createPaginatedRowModel(), sortedRowModel: createSortedRowModel(sortFns), filteredRowModel: createFilteredRowModel(filterFns), diff --git a/docs/framework/react/reference/index/functions/useTable.md b/docs/framework/react/reference/index/functions/useTable.md index 9ccbbd6356..d28dfafc1b 100644 --- a/docs/framework/react/reference/index/functions/useTable.md +++ b/docs/framework/react/reference/index/functions/useTable.md @@ -52,8 +52,8 @@ subscriptions. ```tsx const table = useTable( { - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, }, diff --git a/docs/framework/react/reference/legacy/functions/useLegacyTable.md b/docs/framework/react/reference/legacy/functions/useLegacyTable.md index 44b191fe9f..3b5e668ea7 100644 --- a/docs/framework/react/reference/legacy/functions/useLegacyTable.md +++ b/docs/framework/react/reference/legacy/functions/useLegacyTable.md @@ -35,19 +35,19 @@ A table instance with the full state subscribed and a `getState()` method This hook is provided as a compatibility layer for migrating from TanStack Table v8. -Use the new `useTable` hook instead with explicit `_features` and `_rowModels`: +Use the new `useTable` hook instead with explicit `features` and `rowModels`: ```tsx // New v9 API -const _features = tableFeatures({ +const features = tableFeatures({ columnFilteringFeature, rowSortingFeature, rowPaginationFeature, }) const table = useTable({ - _features, - _rowModels: { + features, + rowModels: { filteredRowModel: createFilteredRowModel(filterFns), sortedRowModel: createSortedRowModel(sortFns), paginatedRowModel: createPaginatedRowModel(), @@ -59,6 +59,6 @@ const table = useTable({ Key differences from v8: - Features are tree-shakeable - only import what you use -- Row models are explicitly passed via `_rowModels` +- Row models are explicitly passed via `rowModels` - Use `table.Subscribe` for fine-grained re-renders - State is accessed via `table.state` after selecting with the 2nd argument diff --git a/docs/framework/react/reference/legacy/interfaces/LegacyRowModelOptions.md b/docs/framework/react/reference/legacy/interfaces/LegacyRowModelOptions.md index cd82a146c2..060090cd58 100644 --- a/docs/framework/react/reference/legacy/interfaces/LegacyRowModelOptions.md +++ b/docs/framework/react/reference/legacy/interfaces/LegacyRowModelOptions.md @@ -29,7 +29,7 @@ Additional aggregation functions to apply to the table. #### Deprecated -Use `_rowModels.groupedRowModel` with `createGroupedRowModel(aggregationFns)` instead. +Use `rowModels.groupedRowModel` with `createGroupedRowModel(aggregationFns)` instead. *** @@ -45,7 +45,7 @@ Additional filter functions to apply to the table. #### Deprecated -Use `_rowModels.filteredRowModel` with `createFilteredRowModel(filterFns)` instead. +Use `rowModels.filteredRowModel` with `createFilteredRowModel(filterFns)` instead. *** @@ -77,7 +77,7 @@ Returns the expanded row model for the table. #### Deprecated -Use `_rowModels.expandedRowModel` with `createExpandedRowModel()` instead. +Use `rowModels.expandedRowModel` with `createExpandedRowModel()` instead. *** @@ -93,7 +93,7 @@ Returns the faceted min/max values for a column. #### Deprecated -Use `_rowModels.facetedMinMaxValues` with `createFacetedMinMaxValues()` instead. +Use `rowModels.facetedMinMaxValues` with `createFacetedMinMaxValues()` instead. *** @@ -109,7 +109,7 @@ Returns the faceted row model for a column. #### Deprecated -Use `_rowModels.facetedRowModel` with `createFacetedRowModel()` instead. +Use `rowModels.facetedRowModel` with `createFacetedRowModel()` instead. *** @@ -125,7 +125,7 @@ Returns the faceted unique values for a column. #### Deprecated -Use `_rowModels.facetedUniqueValues` with `createFacetedUniqueValues()` instead. +Use `rowModels.facetedUniqueValues` with `createFacetedUniqueValues()` instead. *** @@ -141,7 +141,7 @@ Returns the filtered row model for the table. #### Deprecated -Use `_rowModels.filteredRowModel` with `createFilteredRowModel(filterFns)` instead. +Use `rowModels.filteredRowModel` with `createFilteredRowModel(filterFns)` instead. *** @@ -157,7 +157,7 @@ Returns the grouped row model for the table. #### Deprecated -Use `_rowModels.groupedRowModel` with `createGroupedRowModel(aggregationFns)` instead. +Use `rowModels.groupedRowModel` with `createGroupedRowModel(aggregationFns)` instead. *** @@ -173,7 +173,7 @@ Returns the paginated row model for the table. #### Deprecated -Use `_rowModels.paginatedRowModel` with `createPaginatedRowModel()` instead. +Use `rowModels.paginatedRowModel` with `createPaginatedRowModel()` instead. *** @@ -189,7 +189,7 @@ Returns the sorted row model for the table. #### Deprecated -Use `_rowModels.sortedRowModel` with `createSortedRowModel(sortFns)` instead. +Use `rowModels.sortedRowModel` with `createSortedRowModel(sortFns)` instead. *** @@ -205,4 +205,4 @@ Additional sort functions to apply to the table. #### Deprecated -Use `_rowModels.sortedRowModel` with `createSortedRowModel(sortFns)` instead. +Use `rowModels.sortedRowModel` with `createSortedRowModel(sortFns)` instead. diff --git a/docs/framework/react/reference/legacy/type-aliases/LegacyTableOptions.md b/docs/framework/react/reference/legacy/type-aliases/LegacyTableOptions.md index 27692999a9..e2b63ee894 100644 --- a/docs/framework/react/reference/legacy/type-aliases/LegacyTableOptions.md +++ b/docs/framework/react/reference/legacy/type-aliases/LegacyTableOptions.md @@ -6,14 +6,14 @@ title: LegacyTableOptions # ~~Type Alias: LegacyTableOptions\~~ ```ts -type LegacyTableOptions = Omit, "_features" | "_rowModels"> & LegacyRowModelOptions; +type LegacyTableOptions = Omit, "features" | "rowModels"> & LegacyRowModelOptions; ``` Defined in: [useLegacyTable.ts:264](https://github.com/TanStack/table/blob/main/packages/react-table/src/useLegacyTable.ts#L264) Legacy v8-style table options that work with useLegacyTable. -This type omits `_features` and `_rowModels` and instead accepts the v8-style +This type omits `features` and `rowModels` and instead accepts the v8-style `get*RowModel` function options. ## Type Parameters @@ -24,4 +24,4 @@ This type omits `_features` and `_rowModels` and instead accepts the v8-style ## Deprecated -This is a compatibility layer for migrating from v8. Use `useTable` with explicit `_features` and `_rowModels` instead. +This is a compatibility layer for migrating from v8. Use `useTable` with explicit `features` and `rowModels` instead. diff --git a/docs/framework/solid/guide/table-state.md b/docs/framework/solid/guide/table-state.md index 447709d85d..da33a0b5a3 100644 --- a/docs/framework/solid/guide/table-state.md +++ b/docs/framework/solid/guide/table-state.md @@ -38,17 +38,17 @@ The Solid adapter provides `solidReactivity(owner)` to the table's `coreReativit ### Feature-based State -State slices are only created for the features that are registered in `_features`. This keeps TanStack Table tree-shakeable and gives TypeScript more accurate state inference. +State slices are only created for the features that are registered in `features`. This keeps TanStack Table tree-shakeable and gives TypeScript more accurate state inference. ```tsx -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, rowSortingFeature, }) const table = createTable({ - _features, - _rowModels: { + features, + rowModels: { paginatedRowModel: createPaginatedRowModel(), sortedRowModel: createSortedRowModel(sortFns), }, @@ -64,7 +64,7 @@ table.atoms.sorting.get() // table.atoms.rowSelection // TypeScript error unless rowSelectionFeature is registered ``` -If `_features` does not include a feature, its state should not be available in `table.atoms`, `table.store.state`, `table.state()`, `initialState`, `state`, or `atoms`. +If `features` does not include a feature, its state should not be available in `table.atoms`, `table.store.state`, `table.state()`, `initialState`, `state`, or `atoms`. ### Accessing Table State @@ -100,8 +100,8 @@ The second argument to `createTable` is a TanStack Store selector. The selected ```tsx const table = createTable( { - _features, - _rowModels: { + features, + rowModels: { paginatedRowModel: createPaginatedRowModel(), }, columns, @@ -192,8 +192,8 @@ If you only need to customize the starting value for some table state, use `init ```tsx const table = createTable({ - _features, - _rowModels: { + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns), paginatedRowModel: createPaginatedRowModel(), }, @@ -247,7 +247,7 @@ import { type PaginationState, } from '@tanstack/solid-table' -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, }) @@ -264,8 +264,8 @@ const dataQuery = useQuery(() => ({ })) const table = createTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, get data() { return dataQuery.data?.rows ?? [] @@ -294,8 +294,8 @@ const [pagination, setPagination] = createSignal({ }) const table = createTable({ - _features, - _rowModels: { + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns), paginatedRowModel: createPaginatedRowModel(), }, @@ -357,8 +357,8 @@ const [sorting, setSorting] = createSignal([ ]) ``` -`TableState` is inferred from the features registered on that table: +`TableState` is inferred from the features registered on that table: ```tsx -type MyTableState = TableState +type MyTableState = TableState ``` diff --git a/docs/framework/solid/reference/functions/createTable.md b/docs/framework/solid/reference/functions/createTable.md index f74d5d1419..d60f35e72a 100644 --- a/docs/framework/solid/reference/functions/createTable.md +++ b/docs/framework/solid/reference/functions/createTable.md @@ -51,8 +51,8 @@ update without invalidating unrelated UI. ```tsx const table = createTable( { - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, }, diff --git a/docs/framework/solid/reference/functions/createTableHook.md b/docs/framework/solid/reference/functions/createTableHook.md index 3fc2b9207e..5509088f56 100644 --- a/docs/framework/solid/reference/functions/createTableHook.md +++ b/docs/framework/solid/reference/functions/createTableHook.md @@ -116,7 +116,7 @@ TFeatures is already known from the createTableHook call; TData is inferred from ##### tableOptions -`Omit`\<`TableOptions`\<`TFeatures`, `TData`\>, `"_features"` \| `"_rowModels"`\> +`Omit`\<`TableOptions`\<`TFeatures`, `TData`\>, `"features"` \| `"rowModels"`\> ##### selector? @@ -252,12 +252,12 @@ export const { useCellContext, useHeaderContext, } = createTableHook({ - _features: tableFeatures({ + features: tableFeatures({ rowPaginationFeature, rowSortingFeature, columnFilteringFeature, }), - _rowModels: { + rowModels: { paginatedRowModel: createPaginatedRowModel(), sortedRowModel: createSortedRowModel(sortFns), filteredRowModel: createFilteredRowModel(filterFns), diff --git a/docs/framework/solid/solid-table.md b/docs/framework/solid/solid-table.md index 561ab79188..dbafdee1a9 100644 --- a/docs/framework/solid/solid-table.md +++ b/docs/framework/solid/solid-table.md @@ -4,7 +4,7 @@ title: Solid Table The `@tanstack/solid-table` adapter wraps `@tanstack/table-core` with Solid-specific reactivity, rendering helpers, and types. It installs the Solid `coreReativityFeature` for you, so table atoms participate in Solid dependency tracking and can update computations with fine-grained precision. -TanStack Table v9 is explicit about what a table uses. Register features with `_features`, and register client-side row model factories with `_rowModels`. The core row model is included by default, so a basic table can use `_rowModels: {}`. +TanStack Table v9 is explicit about what a table uses. Register features with `features`, and register client-side row model factories with `rowModels`. The core row model is included by default, so a basic table can use `rowModels: {}`. ## Creating a Table @@ -19,9 +19,9 @@ type Person = { age: number } -const _features = tableFeatures({}) +const features = tableFeatures({}) -const columns: Array> = [ +const columns: Array> = [ { accessorKey: 'firstName', header: 'First name', @@ -31,8 +31,8 @@ const columns: Array> = [ function App(props: { data: Person[] }) { const table = createTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, get data() { return props.data @@ -43,7 +43,7 @@ function App(props: { data: Person[] }) { } ``` -For feature-specific row models, register the feature and put the row model factory under `_rowModels`. +For feature-specific row models, register the feature and put the row model factory under `rowModels`. ```tsx import { @@ -55,14 +55,14 @@ import { tableFeatures, } from '@tanstack/solid-table' -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, rowSortingFeature, }) const tableOptions = { - _features, - _rowModels: { + features, + rowModels: { paginatedRowModel: createPaginatedRowModel(), sortedRowModel: createSortedRowModel(sortFns), }, @@ -84,7 +84,7 @@ import { type PaginationState, } from '@tanstack/solid-table' -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, }) @@ -94,8 +94,8 @@ const paginationAtom = createAtom({ }) const table = createTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, atoms: { @@ -130,14 +130,14 @@ Use `table.FlexRender` to render column `header`, `cell`, and `footer` definitio ## createTableHook -`createTableHook` creates an app-specific table creator. Use it when multiple tables should share `_features`, `_rowModels`, default options, column helpers, and component conventions. +`createTableHook` creates an app-specific table creator. Use it when multiple tables should share `features`, `rowModels`, default options, column helpers, and component conventions. ```tsx import { createTableHook, tableFeatures } from '@tanstack/solid-table' const { createAppTable, createAppColumnHelper } = createTableHook({ - _features: tableFeatures({}), - _rowModels: {}, + features: tableFeatures({}), + rowModels: {}, }) const columnHelper = createAppColumnHelper() diff --git a/docs/framework/svelte/guide/table-state.md b/docs/framework/svelte/guide/table-state.md index d451400f63..082814c273 100644 --- a/docs/framework/svelte/guide/table-state.md +++ b/docs/framework/svelte/guide/table-state.md @@ -38,17 +38,17 @@ The Svelte adapter provides `svelteReactivity()` to the table's `coreReativityFe ### Feature-based State -State slices are only created for the features that are registered in `_features`. This keeps TanStack Table tree-shakeable and gives TypeScript more accurate state inference. +State slices are only created for the features that are registered in `features`. This keeps TanStack Table tree-shakeable and gives TypeScript more accurate state inference. ```ts -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, rowSortingFeature, }) const table = createTable({ - _features, - _rowModels: { + features, + rowModels: { paginatedRowModel: createPaginatedRowModel(), sortedRowModel: createSortedRowModel(sortFns), }, @@ -64,7 +64,7 @@ table.atoms.sorting.get() // table.atoms.rowSelection // TypeScript error unless rowSelectionFeature is registered ``` -If `_features` does not include a feature, its state should not be available in `table.atoms`, `table.store.state`, `table.state`, `initialState`, `state`, or `atoms`. +If `features` does not include a feature, its state should not be available in `table.atoms`, `table.store.state`, `table.state`, `initialState`, `state`, or `atoms`. ### Accessing Table State @@ -100,8 +100,8 @@ The second argument to `createTable` is a TanStack Store selector. The selected ```ts const table = createTable( { - _features, - _rowModels: { + features, + rowModels: { paginatedRowModel: createPaginatedRowModel(), }, columns, @@ -171,8 +171,8 @@ If you only need to customize the starting value for some table state, use `init ```ts const table = createTable({ - _features, - _rowModels: { + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns), paginatedRowModel: createPaginatedRowModel(), }, @@ -226,7 +226,7 @@ import { type PaginationState, } from '@tanstack/svelte-table' -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, }) @@ -238,8 +238,8 @@ const paginationAtom = createAtom({ const pagination = useSelector(paginationAtom) const table = createTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, get data() { return dataQuery.data?.rows ?? [] @@ -270,8 +270,8 @@ let pagination: PaginationState = $state({ }) const table = createTable({ - _features, - _rowModels: { + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns), paginatedRowModel: createPaginatedRowModel(), }, @@ -331,8 +331,8 @@ let sorting: SortingState = $state([ ]) ``` -`TableState` is inferred from the features registered on that table: +`TableState` is inferred from the features registered on that table: ```ts -type MyTableState = TableState +type MyTableState = TableState ``` diff --git a/docs/framework/svelte/reference/functions/createTable.md b/docs/framework/svelte/reference/functions/createTable.md index e07b5ac688..3035e3c3fb 100644 --- a/docs/framework/svelte/reference/functions/createTable.md +++ b/docs/framework/svelte/reference/functions/createTable.md @@ -52,8 +52,8 @@ updates read table APIs such as `getRowModel()`. ``` -For feature-specific row models, register the feature and put the row model factory under `_rowModels`. +For feature-specific row models, register the feature and put the row model factory under `rowModels`. ```svelte -{#snippet headerCell(header: Header)} +{#snippet headerCell(header: Header)}
{#if !header.isPlaceholder} diff --git a/examples/svelte/column-resizing-performant/src/App.svelte b/examples/svelte/column-resizing-performant/src/App.svelte index 905373dae2..7e40496090 100644 --- a/examples/svelte/column-resizing-performant/src/App.svelte +++ b/examples/svelte/column-resizing-performant/src/App.svelte @@ -11,12 +11,12 @@ import type { Person } from './makeData' import './index.css' - const _features = tableFeatures({ + const features = tableFeatures({ columnSizingFeature, columnResizingFeature, }) - const columnHelper = createColumnHelper() + const columnHelper = createColumnHelper() const columns = columnHelper.columns([ columnHelper.group({ @@ -65,8 +65,8 @@ const table = createTable( { - _features, - _rowModels: {}, + features, + rowModels: {}, columns, get data() { return data diff --git a/examples/svelte/column-resizing/src/App.svelte b/examples/svelte/column-resizing/src/App.svelte index 1f32cda8a3..1e8dc871c7 100644 --- a/examples/svelte/column-resizing/src/App.svelte +++ b/examples/svelte/column-resizing/src/App.svelte @@ -14,12 +14,12 @@ import { makeData, type Person } from './makeData' import './index.css' - const _features = tableFeatures({ + const features = tableFeatures({ columnResizingFeature, columnSizingFeature, }) - const columnHelper = createColumnHelper() + const columnHelper = createColumnHelper() const columns = columnHelper.columns([ columnHelper.group({ @@ -76,8 +76,8 @@ const table = createTable( { - _features, - _rowModels: {}, + features, + rowModels: {}, columns, get data() { return data diff --git a/examples/svelte/column-sizing/src/App.svelte b/examples/svelte/column-sizing/src/App.svelte index beefd91afe..bcb225f3ed 100644 --- a/examples/svelte/column-sizing/src/App.svelte +++ b/examples/svelte/column-sizing/src/App.svelte @@ -9,9 +9,9 @@ import { makeData, type Person } from './makeData' import './index.css' - const _features = tableFeatures({ columnSizingFeature }) + const features = tableFeatures({ columnSizingFeature }) - const columnHelper = createColumnHelper() + const columnHelper = createColumnHelper() const columns = columnHelper.columns([ columnHelper.accessor('firstName', { @@ -54,8 +54,8 @@ const table = createTable( { - _features, - _rowModels: {}, + features, + rowModels: {}, columns, get data() { return data diff --git a/examples/svelte/column-visibility/src/App.svelte b/examples/svelte/column-visibility/src/App.svelte index dd317006ae..be5bf27fec 100644 --- a/examples/svelte/column-visibility/src/App.svelte +++ b/examples/svelte/column-visibility/src/App.svelte @@ -18,7 +18,7 @@ const refreshData = () => { data = makeData(1_000) } const stressTest = () => { data = makeData(500_000) } - const columns: ColumnDef[] = [ + const columns: ColumnDef[] = [ { header: 'Name', footer: (props) => props.column.id, @@ -70,7 +70,7 @@ }, ] - const _features = tableFeatures({ columnVisibilityFeature }) + const features = tableFeatures({ columnVisibilityFeature }) let columnVisibility = $state({}) @@ -81,8 +81,8 @@ } const table = createTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, get data() { return data }, diff --git a/examples/svelte/composable-tables/src/components/UsersTable.svelte b/examples/svelte/composable-tables/src/components/UsersTable.svelte index a83910e657..a09cab1763 100644 --- a/examples/svelte/composable-tables/src/components/UsersTable.svelte +++ b/examples/svelte/composable-tables/src/components/UsersTable.svelte @@ -62,7 +62,7 @@ }), ]) - // Create the table - _features and _rowModels are already configured! + // Create the table - features and rowModels are already configured! const table = createAppTable({ columns, get data() { diff --git a/examples/svelte/composable-tables/src/hooks/table.ts b/examples/svelte/composable-tables/src/hooks/table.ts index 71ad486cf5..2c94570ac2 100644 --- a/examples/svelte/composable-tables/src/hooks/table.ts +++ b/examples/svelte/composable-tables/src/hooks/table.ts @@ -55,14 +55,14 @@ export const { useHeaderContext, } = createTableHook({ // Features are set once here and shared across all tables - _features: tableFeatures({ + features: tableFeatures({ columnFilteringFeature, rowPaginationFeature, rowSortingFeature, }), // Row models are set once here - _rowModels: { + rowModels: { sortedRowModel: createSortedRowModel(sortFns), filteredRowModel: createFilteredRowModel(filterFns), paginatedRowModel: createPaginatedRowModel(), diff --git a/examples/svelte/expanding/src/App.svelte b/examples/svelte/expanding/src/App.svelte index 78d432d4e3..e9c34f6238 100644 --- a/examples/svelte/expanding/src/App.svelte +++ b/examples/svelte/expanding/src/App.svelte @@ -21,7 +21,7 @@ import type { Person } from './makeData' import './index.css' - const _features = tableFeatures({ + const features = tableFeatures({ columnFilteringFeature, rowExpandingFeature, rowPaginationFeature, @@ -29,7 +29,7 @@ rowSelectionFeature, }) - const columnHelper = createColumnHelper() + const columnHelper = createColumnHelper() // Svelte action to set indeterminate property on checkbox inputs function setIndeterminate(node: HTMLInputElement, value: boolean) { @@ -78,8 +78,8 @@ const table = createTable( { - _features, - _rowModels: { + features, + rowModels: { expandedRowModel: createExpandedRowModel(), filteredRowModel: createFilteredRowModel(filterFns), paginatedRowModel: createPaginatedRowModel(), @@ -254,7 +254,7 @@
{JSON.stringify(table.state, null, 2)}
-{#snippet Filter(column: Column, table: SvelteTable)} +{#snippet Filter(column: Column, table: SvelteTable)} {@const firstValue = table .getPreFilteredRowModel() .flatRows[0]?.getValue(column.id)} diff --git a/examples/svelte/filtering/src/App.svelte b/examples/svelte/filtering/src/App.svelte index 68cacca4de..ec34f90012 100644 --- a/examples/svelte/filtering/src/App.svelte +++ b/examples/svelte/filtering/src/App.svelte @@ -20,14 +20,14 @@ import './index.css' import { makeData, type Person } from './makeData' - const _features = tableFeatures({ + const features = tableFeatures({ columnFilteringFeature, globalFilteringFeature, columnFacetingFeature, rowPaginationFeature, }) - const columns: Array> = [ + const columns: Array> = [ { header: 'Name', footer: (props) => props.column.id, @@ -88,8 +88,8 @@ const table = createTable( { - _features, - _rowModels: { + features, + rowModels: { facetedRowModel: createFacetedRowModel(), facetedMinMaxValues: createFacetedMinMaxValues(), facetedUniqueValues: createFacetedUniqueValues(), diff --git a/examples/svelte/filters-faceted/src/App.svelte b/examples/svelte/filters-faceted/src/App.svelte index 22e70369c8..21052d0c63 100644 --- a/examples/svelte/filters-faceted/src/App.svelte +++ b/examples/svelte/filters-faceted/src/App.svelte @@ -20,14 +20,14 @@ import './index.css' import { makeData, type Person } from './makeData' - const _features = tableFeatures({ + const features = tableFeatures({ columnFilteringFeature, globalFilteringFeature, columnFacetingFeature, rowPaginationFeature, }) - const columns: Array> = [ + const columns: Array> = [ { header: 'Name', footer: (props) => props.column.id, @@ -85,8 +85,8 @@ const table = createTable( { - _features, - _rowModels: { + features, + rowModels: { facetedRowModel: createFacetedRowModel(), facetedMinMaxValues: createFacetedMinMaxValues(), facetedUniqueValues: createFacetedUniqueValues(), diff --git a/examples/svelte/filters-fuzzy/src/App.svelte b/examples/svelte/filters-fuzzy/src/App.svelte index 835d00958b..9d8e4c96ca 100644 --- a/examples/svelte/filters-fuzzy/src/App.svelte +++ b/examples/svelte/filters-fuzzy/src/App.svelte @@ -20,16 +20,16 @@ import { makeData, type Person } from './makeData' import type { Column, FilterFn, SortFn } from '@tanstack/svelte-table' - const _features = tableFeatures({ + const features = tableFeatures({ columnFilteringFeature, globalFilteringFeature, rowSortingFeature, rowPaginationFeature, }) - const columnHelper = createColumnHelper() + const columnHelper = createColumnHelper() - const fuzzyFilter: FilterFn = ( + const fuzzyFilter: FilterFn = ( row, columnId, value, @@ -40,7 +40,7 @@ return itemRank.passed } - const fuzzySort: SortFn = ( + const fuzzySort: SortFn = ( rowA, rowB, columnId, @@ -85,8 +85,8 @@ const table = createTable( { - _features, - _rowModels: { + features, + rowModels: { filteredRowModel: createFilteredRowModel({ ...filterFns, fuzzy: fuzzyFilter, diff --git a/examples/svelte/grouping/src/App.svelte b/examples/svelte/grouping/src/App.svelte index 8cbc1c9dea..a0a99a087e 100644 --- a/examples/svelte/grouping/src/App.svelte +++ b/examples/svelte/grouping/src/App.svelte @@ -21,14 +21,14 @@ import './index.css' const { createAppTable, createAppColumnHelper } = createTableHook({ - _features: { + features: { columnFilteringFeature, columnGroupingFeature, rowExpandingFeature, rowPaginationFeature, rowSortingFeature, }, - _rowModels: { + rowModels: { expandedRowModel: createExpandedRowModel(), filteredRowModel: createFilteredRowModel(filterFns), groupedRowModel: createGroupedRowModel(aggregationFns), diff --git a/examples/svelte/kitchen-sink/src/App.svelte b/examples/svelte/kitchen-sink/src/App.svelte index d7f94b092f..8cf78e9b85 100644 --- a/examples/svelte/kitchen-sink/src/App.svelte +++ b/examples/svelte/kitchen-sink/src/App.svelte @@ -64,8 +64,8 @@ } const { createAppTable, createAppColumnHelper } = createTableHook({ - _features: stockFeatures, - _rowModels: { + features: stockFeatures, + rowModels: { expandedRowModel: createExpandedRowModel(), filteredRowModel: createFilteredRowModel({ ...filterFns, diff --git a/examples/svelte/pagination/src/App.svelte b/examples/svelte/pagination/src/App.svelte index afb6f9a40b..c9a02b7aa9 100644 --- a/examples/svelte/pagination/src/App.svelte +++ b/examples/svelte/pagination/src/App.svelte @@ -11,11 +11,11 @@ import type { Person } from './makeData' import './index.css' - const _features = tableFeatures({ + const features = tableFeatures({ rowPaginationFeature, }) - const columnHelper = createColumnHelper() + const columnHelper = createColumnHelper() const columns = columnHelper.columns([ columnHelper.accessor('firstName', { @@ -52,8 +52,8 @@ const table = createTable( { - _features, - _rowModels: { + features, + rowModels: { paginatedRowModel: createPaginatedRowModel(), }, columns, diff --git a/examples/svelte/row-pinning/src/App.svelte b/examples/svelte/row-pinning/src/App.svelte index a0f6293f95..362762984a 100644 --- a/examples/svelte/row-pinning/src/App.svelte +++ b/examples/svelte/row-pinning/src/App.svelte @@ -24,7 +24,7 @@ import type { Person } from './makeData' import './index.css' - const _features = tableFeatures({ + const features = tableFeatures({ columnSizingFeature, rowPinningFeature, rowExpandingFeature, @@ -50,8 +50,8 @@ const table = createTable( { debugTable: true, - _features, - _rowModels: { + features, + rowModels: { filteredRowModel: createFilteredRowModel(filterFns), expandedRowModel: createExpandedRowModel(), paginatedRowModel: createPaginatedRowModel(), @@ -179,7 +179,7 @@
{header.isPlaceholder ? null : (
{table .getRowModel() - .rows.map((row: Row) => ( + .rows.map((row: Row) => (
{header.isPlaceholder ? null : (
{table .getRowModel() - .rows.map((row: Row) => ( + .rows.map((row: Row) => (
{header.isPlaceholder ? null : ( @@ -132,11 +132,11 @@ export default defineComponent({
{header.isPlaceholder ? null : ( diff --git a/examples/vue/column-groups/src/App.tsx b/examples/vue/column-groups/src/App.tsx index e51f8c999c..ef67c9474e 100644 --- a/examples/vue/column-groups/src/App.tsx +++ b/examples/vue/column-groups/src/App.tsx @@ -10,9 +10,9 @@ import type { } from '@tanstack/vue-table' import type { Person } from './makeData' -const _features = tableFeatures({}) +const features = tableFeatures({}) -const columns: Array> = [ +const columns: Array> = [ { header: 'Name', footer: (props) => props.column.id, @@ -79,7 +79,7 @@ export default defineComponent({ const table = useTable({ debugTable: true, - _features, + features, columns, get data() { return data.value @@ -101,10 +101,10 @@ export default defineComponent({
{header.isPlaceholder ? null : ( @@ -118,11 +118,11 @@ export default defineComponent({
{header.isPlaceholder ? null : ( diff --git a/examples/vue/column-ordering/src/App.vue b/examples/vue/column-ordering/src/App.vue index 2d110f29fb..f55bd611f3 100644 --- a/examples/vue/column-ordering/src/App.vue +++ b/examples/vue/column-ordering/src/App.vue @@ -13,12 +13,12 @@ import { makeData } from './makeData' import type { Person } from './makeData' import type { Column } from '@tanstack/vue-table' -const _features = tableFeatures({ +const features = tableFeatures({ columnOrderingFeature, columnVisibilityFeature, }) -const columnHelper = createColumnHelper() +const columnHelper = createColumnHelper() const data = ref(makeData(20)) @@ -80,7 +80,7 @@ const stressTest = () => { const table = useTable( { - _features, + features, data, get columns() { return columns.value @@ -100,12 +100,12 @@ const randomizeColumns = () => { faker.helpers.shuffle( table .getAllLeafColumns() - .map((column: Column) => column.id), + .map((column: Column) => column.id), ), ) } -function toggleColumnVisibility(column: Column) { +function toggleColumnVisibility(column: Column) { table.setColumnVisibility({ ...table.state.columnVisibility, [column.id]: !column.getIsVisible(), @@ -115,7 +115,7 @@ function toggleColumnVisibility(column: Column) { function toggleAllColumnsVisibility() { table .getAllLeafColumns() - .forEach((column: Column) => { + .forEach((column: Column) => { toggleColumnVisibility(column) }) } diff --git a/examples/vue/column-pinning-split/src/App.vue b/examples/vue/column-pinning-split/src/App.vue index 3bc13726eb..badf4048ae 100644 --- a/examples/vue/column-pinning-split/src/App.vue +++ b/examples/vue/column-pinning-split/src/App.vue @@ -11,11 +11,11 @@ import { ref } from 'vue' import { makeData } from './makeData' import type { Person } from './makeData' -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, }) -const columnHelper = createColumnHelper() +const columnHelper = createColumnHelper() const INITIAL_PAGE_INDEX = 0 @@ -73,8 +73,8 @@ const columns = ref( const table = useTable( { - _features, - _rowModels: { + features, + rowModels: { paginatedRowModel: createPaginatedRowModel(), }, data, diff --git a/examples/vue/column-pinning-sticky/src/App.vue b/examples/vue/column-pinning-sticky/src/App.vue index 3bc13726eb..badf4048ae 100644 --- a/examples/vue/column-pinning-sticky/src/App.vue +++ b/examples/vue/column-pinning-sticky/src/App.vue @@ -11,11 +11,11 @@ import { ref } from 'vue' import { makeData } from './makeData' import type { Person } from './makeData' -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, }) -const columnHelper = createColumnHelper() +const columnHelper = createColumnHelper() const INITIAL_PAGE_INDEX = 0 @@ -73,8 +73,8 @@ const columns = ref( const table = useTable( { - _features, - _rowModels: { + features, + rowModels: { paginatedRowModel: createPaginatedRowModel(), }, data, diff --git a/examples/vue/column-pinning/src/App.vue b/examples/vue/column-pinning/src/App.vue index f421e7080a..8a930151d1 100644 --- a/examples/vue/column-pinning/src/App.vue +++ b/examples/vue/column-pinning/src/App.vue @@ -16,13 +16,13 @@ import type { Column } from '@tanstack/vue-table' const data = ref(makeData(1_000)) -const _features = tableFeatures({ +const features = tableFeatures({ columnOrderingFeature, columnPinningFeature, columnVisibilityFeature, }) -const columnHelper = createColumnHelper() +const columnHelper = createColumnHelper() const columns = ref( columnHelper.columns([ @@ -84,7 +84,7 @@ const stressTest = () => { const table = useTable( { - _features, + features, data, get columns() { return columns.value @@ -105,12 +105,12 @@ const randomizeColumns = () => { faker.helpers.shuffle( table .getAllLeafColumns() - .map((column: Column) => column.id), + .map((column: Column) => column.id), ), ) } -function toggleColumnVisibility(column: Column) { +function toggleColumnVisibility(column: Column) { table.setColumnVisibility({ ...table.state.columnVisibility, [column.id]: !column.getIsVisible(), @@ -120,7 +120,7 @@ function toggleColumnVisibility(column: Column) { function toggleAllColumnsVisibility() { table .getAllLeafColumns() - .forEach((column: Column) => { + .forEach((column: Column) => { toggleColumnVisibility(column) }) } diff --git a/examples/vue/column-resizing-performant/src/App.vue b/examples/vue/column-resizing-performant/src/App.vue index 9a33ddfeb3..eb77fa8a94 100644 --- a/examples/vue/column-resizing-performant/src/App.vue +++ b/examples/vue/column-resizing-performant/src/App.vue @@ -11,11 +11,11 @@ import { ref } from 'vue' import { makeData } from './makeData' import type { Person } from './makeData' -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, }) -const columnHelper = createColumnHelper() +const columnHelper = createColumnHelper() const INITIAL_PAGE_INDEX = 0 @@ -73,8 +73,8 @@ const columns = ref( const table = useTable( { - _features, - _rowModels: { + features, + rowModels: { paginatedRowModel: createPaginatedRowModel(), }, data, diff --git a/examples/vue/column-resizing/src/App.vue b/examples/vue/column-resizing/src/App.vue index 3bc13726eb..badf4048ae 100644 --- a/examples/vue/column-resizing/src/App.vue +++ b/examples/vue/column-resizing/src/App.vue @@ -11,11 +11,11 @@ import { ref } from 'vue' import { makeData } from './makeData' import type { Person } from './makeData' -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, }) -const columnHelper = createColumnHelper() +const columnHelper = createColumnHelper() const INITIAL_PAGE_INDEX = 0 @@ -73,8 +73,8 @@ const columns = ref( const table = useTable( { - _features, - _rowModels: { + features, + rowModels: { paginatedRowModel: createPaginatedRowModel(), }, data, diff --git a/examples/vue/column-sizing/src/App.vue b/examples/vue/column-sizing/src/App.vue index 3bc13726eb..badf4048ae 100644 --- a/examples/vue/column-sizing/src/App.vue +++ b/examples/vue/column-sizing/src/App.vue @@ -11,11 +11,11 @@ import { ref } from 'vue' import { makeData } from './makeData' import type { Person } from './makeData' -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, }) -const columnHelper = createColumnHelper() +const columnHelper = createColumnHelper() const INITIAL_PAGE_INDEX = 0 @@ -73,8 +73,8 @@ const columns = ref( const table = useTable( { - _features, - _rowModels: { + features, + rowModels: { paginatedRowModel: createPaginatedRowModel(), }, data, diff --git a/examples/vue/column-visibility/src/App.tsx b/examples/vue/column-visibility/src/App.tsx index faca800839..9415ef2223 100644 --- a/examples/vue/column-visibility/src/App.tsx +++ b/examples/vue/column-visibility/src/App.tsx @@ -16,9 +16,9 @@ import type { } from '@tanstack/vue-table' import type { Person } from './makeData' -const _features = tableFeatures({ columnVisibilityFeature }) +const features = tableFeatures({ columnVisibilityFeature }) -const columns: Array> = [ +const columns: Array> = [ { header: 'Name', footer: (props) => props.column.id, @@ -85,7 +85,7 @@ export default defineComponent({ const table = useTable({ debugTable: true, - _features, + features, columns, get data() { return data.value @@ -116,7 +116,7 @@ export default defineComponent({ {table .getAllLeafColumns() - .map((column: Column) => ( + .map((column: Column) => (
{header.isPlaceholder ? null : ( @@ -151,11 +151,11 @@ export default defineComponent({
{header.isPlaceholder ? null : ( diff --git a/examples/vue/composable-tables/src/hooks/table.ts b/examples/vue/composable-tables/src/hooks/table.ts index a17022f5a7..a351fe8738 100644 --- a/examples/vue/composable-tables/src/hooks/table.ts +++ b/examples/vue/composable-tables/src/hooks/table.ts @@ -43,7 +43,7 @@ import type { // This is needed to break the circular inference chain caused by the component // files (table-components, cell-components, header-components) importing context // functions from this file, while this file imports from those component files. -const _features = tableFeatures({ +const features = tableFeatures({ columnFilteringFeature, globalFilteringFeature, rowPaginationFeature, @@ -51,8 +51,8 @@ const _features = tableFeatures({ }) const _hook = createTableHook({ - _features, - _rowModels: { + features, + rowModels: { filteredRowModel: createFilteredRowModel(filterFns), paginatedRowModel: createPaginatedRowModel(), sortedRowModel: createSortedRowModel(sortFns), @@ -87,18 +87,18 @@ export const useAppTable = _hook.useAppTable // TypeScript cannot infer the types of these when the component files that // import them are also imported by this module (circular dependency). export const useTableContext: () => VueTable< - typeof _features, + typeof features, TData > = _hook.useTableContext export const useCellContext: () => Cell< - typeof _features, + typeof features, any, TValue > = _hook.useCellContext export const useHeaderContext: () => Header< - typeof _features, + typeof features, any, TValue > = _hook.useHeaderContext diff --git a/examples/vue/expanding/src/App.tsx b/examples/vue/expanding/src/App.tsx index a72af6bb64..0036eb652c 100644 --- a/examples/vue/expanding/src/App.tsx +++ b/examples/vue/expanding/src/App.tsx @@ -27,7 +27,7 @@ import type { } from '@tanstack/vue-table' import type { Person } from './makeData' -const _features = tableFeatures({ +const features = tableFeatures({ columnFilteringFeature, rowExpandingFeature, rowPaginationFeature, @@ -35,7 +35,7 @@ const _features = tableFeatures({ rowSelectionFeature, }) -const columnHelper = createColumnHelper() +const columnHelper = createColumnHelper() const IndeterminateCheckbox = defineComponent({ name: 'IndeterminateCheckbox', @@ -67,8 +67,8 @@ const IndeterminateCheckbox = defineComponent({ }) function renderFilter( - column: Column, - table: Table, + column: Column, + table: Table, ) { const firstValue = table .getPreFilteredRowModel() @@ -196,8 +196,8 @@ export default defineComponent({ ]) const table = useTable({ - _features, - _rowModels: { + features, + rowModels: { expandedRowModel: createExpandedRowModel(), filteredRowModel: createFilteredRowModel(filterFns), paginatedRowModel: createPaginatedRowModel(), @@ -226,10 +226,10 @@ export default defineComponent({
{header.isPlaceholder ? null : (
@@ -248,11 +248,11 @@ export default defineComponent({
{header.isPlaceholder ? null : ( @@ -108,11 +108,11 @@ export default defineComponent({
} @@ -347,8 +347,8 @@ Correct: ```tsx // Module scope = stable identity. -const _features = tableFeatures({ rowSortingFeature }) -const columns: ColumnDef[] = [ +const features = tableFeatures({ rowSortingFeature }) +const columns: ColumnDef[] = [ /* … */ ] ``` @@ -373,8 +373,8 @@ Correct: ```tsx import { useTable, tableFeatures } from '@tanstack/react-table' -const _features = tableFeatures({}) -const table = useTable({ _features, _rowModels: {}, columns, data }) +const features = tableFeatures({}) +const table = useTable({ features, rowModels: {}, columns, data }) ``` `useLegacyTable` is a migration shim for incrementally upgrading v8 codebases. It bundles every feature, lacks `table.Subscribe`, and is deprecated in v9 / scheduled for removal in v10. New code uses `useTable`. diff --git a/packages/react-table/skills/react/migrate-v8-to-v9/SKILL.md b/packages/react-table/skills/react/migrate-v8-to-v9/SKILL.md index 884026f82a..09aa88bd62 100644 --- a/packages/react-table/skills/react/migrate-v8-to-v9/SKILL.md +++ b/packages/react-table/skills/react/migrate-v8-to-v9/SKILL.md @@ -4,8 +4,8 @@ description: > Mechanical breaking-change migration from `@tanstack/react-table` v8 to v9. Every v8-shaped option, type, or method an agent will reproduce from muscle memory has a v9 equivalent enumerated below: `useReactTable` → `useTable`, - root `get*RowModel` options → `_rowModels` with factory + *Fns parameter, - `createColumnHelper` → `createColumnHelper`, + root `get*RowModel` options → `rowModels` with factory + *Fns parameter, + `createColumnHelper` → `createColumnHelper`, `table.getState()` → `table.state` / `table.store.state` / `table.atoms.X.get()`, `sortingFn` → `sortFn`, `enablePinning` → split, `_`-prefixed APIs unprefixed, `ColumnSizing` split into `columnSizingFeature` + `columnResizingFeature`. @@ -28,7 +28,7 @@ sources: - TanStack/table:examples/react/basic-use-table/src/main.tsx --- -This skill builds on `tanstack-table/state-management` and `tanstack-table/react/table-state`. Read those first — `state-management` explains _why_ v9 split out `_features` / `_rowModels`, and `table-state` shows the new reactivity model. +This skill builds on `tanstack-table/state-management` and `tanstack-table/react/table-state`. Read those first — `state-management` explains _why_ v9 split out `features` / `rowModels`, and `table-state` shows the new reactivity model. ## Two migration paths @@ -102,11 +102,11 @@ import { sortFns, } from '@tanstack/react-table' -const _features = tableFeatures({ rowSortingFeature }) -const columnHelper = createColumnHelper() +const features = tableFeatures({ rowSortingFeature }) +const columnHelper = createColumnHelper() const table = useTable({ - _features, - _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, // factory takes *Fns + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, // factory takes *Fns columns, data, }) @@ -151,7 +151,7 @@ useReactTable({ }) // v9 — explicit -const _features = tableFeatures({ +const features = tableFeatures({ columnSizingFeature, // fixed widths columnResizingFeature, // drag-to-resize (separate feature) }) @@ -169,7 +169,7 @@ declare module '@tanstack/react-table' { } // v9 -type MyDef = ColumnDef +type MyDef = ColumnDef declare module '@tanstack/react-table' { interface ColumnMeta< TFeatures extends TableFeatures, @@ -218,7 +218,7 @@ function App({ data }) { const table = useLegacyTable({ columns, data, - // v8-style root options — mapped to v9 _rowModels under the hood + // v8-style root options — mapped to v9 rowModels under the hood getCoreRowModel: getCoreRowModel(), getSortedRowModel: getSortedRowModel(), getPaginationRowModel: getPaginationRowModel(), @@ -260,11 +260,11 @@ Correct: ```tsx import { useTable, tableFeatures } from '@tanstack/react-table' -const _features = tableFeatures({}) -const table = useTable({ _features, _rowModels: {}, data, columns }) +const features = tableFeatures({}) +const table = useTable({ features, rowModels: {}, data, columns }) ``` -`useReactTable` is the v8 entry point and won't have `table.Subscribe` / `table.atoms`. `getCoreRowModel()` as an option was removed — core is automatic; non-core models move into `_rowModels` as factories that take their \*Fns parameter. +`useReactTable` is the v8 entry point and won't have `table.Subscribe` / `table.atoms`. `getCoreRowModel()` as an option was removed — core is automatic; non-core models move into `rowModels` as factories that take their \*Fns parameter. Source: PR #6202; `packages/react-table/src/useTable.ts`. ### CRITICAL `createSortedRowModel()` without `sortFns` @@ -272,7 +272,7 @@ Source: PR #6202; `packages/react-table/src/useTable.ts`. Wrong: ```tsx -_rowModels: { +rowModels: { sortedRowModel: createSortedRowModel() } ``` @@ -281,7 +281,7 @@ Correct: ```tsx import { createSortedRowModel, sortFns } from '@tanstack/react-table' -_rowModels: { +rowModels: { sortedRowModel: createSortedRowModel(sortFns) } ``` @@ -300,10 +300,10 @@ const columnHelper = createColumnHelper() Correct: ```tsx -const columnHelper = createColumnHelper() +const columnHelper = createColumnHelper() ``` -v9 requires ``. `typeof _features` is the standard idiom — declare features once and reuse the type. +v9 requires ``. `typeof features` is the standard idiom — declare features once and reuse the type. Source: `docs/framework/react/guide/migrating.md`. ### CRITICAL `table.getState()` reads on v9 @@ -337,15 +337,15 @@ Source: `docs/framework/react/guide/migrating.md`; `examples/react/basic-subscri Wrong: ```tsx -useTable({ _features, _rowModels: {}, columns, data, enablePinning: true }) +useTable({ features, rowModels: {}, columns, data, enablePinning: true }) ``` Correct: ```tsx useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, enableColumnPinning: true, @@ -468,10 +468,10 @@ import { createSortedRowModel, sortFns, } from '@tanstack/react-table' -const _features = tableFeatures({ rowSortingFeature }) +const features = tableFeatures({ rowSortingFeature }) const table = useTable({ - _features, - _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, data, }) @@ -484,5 +484,5 @@ Source: maintainer interview (Phase 4). - `tanstack-table/react/getting-started` — the v9 minimum-viable shape. - `tanstack-table/react/table-state` — replacing `getState()` with selectors / ``. -- `tanstack-table/react/production-readiness` — tree-shaking with `_features` (the whole point of the v9 redesign). +- `tanstack-table/react/production-readiness` — tree-shaking with `features` (the whole point of the v9 redesign). - `tanstack-table/react/react-subscribe-compiler-compat` — fixes the v8-React-Compiler "incompatible library" warning. diff --git a/packages/react-table/skills/react/production-readiness/SKILL.md b/packages/react-table/skills/react/production-readiness/SKILL.md index e20a948c93..3161805663 100644 --- a/packages/react-table/skills/react/production-readiness/SKILL.md +++ b/packages/react-table/skills/react/production-readiness/SKILL.md @@ -2,8 +2,8 @@ name: react/production-readiness description: > Ship-ready optimizations for `@tanstack/react-table` v9: tree-shake the - bundle by registering ONLY the `_features` you actually use; memoize - `_features`, `data`, and `columns` for stable identity; replace + bundle by registering ONLY the `features` you actually use; memoize + `features`, `data`, and `columns` for stable identity; replace `(state) => state` with narrow selectors or per-slice `useSelector(table.atoms.)` subscriptions; and push state-driven re-renders down the tree with `` / `` so the @@ -26,7 +26,7 @@ sources: - TanStack/table:examples/react/kitchen-sink/src/main.tsx --- -This skill builds on `tanstack-table/state-management` and `tanstack-table/react/table-state`. Read those first — `_features` tree-shaking and the atom reactivity model are the foundation; this skill is about _which_ of the patterns introduced there you actually need in production. +This skill builds on `tanstack-table/state-management` and `tanstack-table/react/table-state`. Read those first — `features` tree-shaking and the atom reactivity model are the foundation; this skill is about _which_ of the patterns introduced there you actually need in production. ## When to optimize @@ -34,16 +34,16 @@ The default `useTable` selector is `(state) => state` — the component re-rende ## Setup — stable references -The biggest single perf win is keeping `_features`, `_rowModels`, `columns`, and `data` references stable across renders. Internal memoization keys off identity, so a new object every render forces full recomputation. +The biggest single perf win is keeping `features`, `rowModels`, `columns`, and `data` references stable across renders. Internal memoization keys off identity, so a new object every render forces full recomputation. ```tsx // ✓ Module scope = stable identity -const _features = tableFeatures({ rowSortingFeature, rowPaginationFeature }) -const _rowModels = { +const features = tableFeatures({ rowSortingFeature, rowPaginationFeature }) +const rowModels = { sortedRowModel: createSortedRowModel(sortFns), paginatedRowModel: createPaginatedRowModel(), } -const columnHelper = createColumnHelper() +const columnHelper = createColumnHelper() const columns = columnHelper.columns([ columnHelper.accessor('firstName', { header: 'First' }), columnHelper.accessor('age', { header: 'Age' }), @@ -54,8 +54,8 @@ const EMPTY: Person[] = [] function MyTable({ data }: { data: Person[] | undefined }) { const table = useTable({ - _features, - _rowModels, + features, + rowModels, columns, data: data ?? EMPTY, }) @@ -64,20 +64,20 @@ function MyTable({ data }: { data: Person[] | undefined }) { ## Core Patterns -### 1. Tree-shake `_features` to only what you use +### 1. Tree-shake `features` to only what you use Avoid `stockFeatures` in production. A sort-only table is ~6–7kb registered explicitly versus ~15–20kb if you import the whole stock set. ```tsx // ✓ Pay only for what you render -const _features = tableFeatures({ +const features = tableFeatures({ rowSortingFeature, rowPaginationFeature, }) // ✗ Ships filtering, faceting, grouping, pinning, expanding, sizing, // resizing, visibility, ordering, row-selection, row-pinning… -const _features = tableFeatures(stockFeatures) +const features = tableFeatures(stockFeatures) ``` Source: `docs/guide/features.md`; maintainer guidance. @@ -88,7 +88,7 @@ Source: `docs/guide/features.md`; maintainer guidance. ```tsx // Narrow to specific slices at the table level. -const table = useTable({ _features, _rowModels, columns, data }, (state) => ({ +const table = useTable({ features, rowModels, columns, data }, (state) => ({ sorting: state.sorting, pagination: state.pagination, })) @@ -106,7 +106,7 @@ A noisy footer that re-renders on every keystroke in a filter doesn't need to re ```tsx function MyTable({ data, columns }) { const table = useTable( - { _features, _rowModels, columns, data }, + { features, rowModels, columns, data }, () => null, // top-level opt-out ) return ( @@ -155,7 +155,7 @@ Wrong: ```tsx import { useTable, stockFeatures, tableFeatures } from '@tanstack/react-table' -const _features = tableFeatures(stockFeatures) // ships every feature +const features = tableFeatures(stockFeatures) // ships every feature ``` Correct: @@ -167,21 +167,21 @@ import { rowSortingFeature, rowPaginationFeature, } from '@tanstack/react-table' -const _features = tableFeatures({ rowSortingFeature, rowPaginationFeature }) +const features = tableFeatures({ rowSortingFeature, rowPaginationFeature }) ``` -Tree-shaking via `_features` is one of the headline reasons for the v9 rewrite. `stockFeatures` exists for migration / "everything on" smoke tests, not production. +Tree-shaking via `features` is one of the headline reasons for the v9 rewrite. `stockFeatures` exists for migration / "everything on" smoke tests, not production. Source: maintainer guidance; `docs/guide/features.md`. -### HIGH Unstable `_features` / `_rowModels` / `columns` references +### HIGH Unstable `features` / `rowModels` / `columns` references Wrong: ```tsx function MyTable({ data }) { - const _features = tableFeatures({ rowSortingFeature }) // new every render - const _rowModels = { sortedRowModel: createSortedRowModel(sortFns) } // new every render - const table = useTable({ _features, _rowModels, columns, data }) + const features = tableFeatures({ rowSortingFeature }) // new every render + const rowModels = { sortedRowModel: createSortedRowModel(sortFns) } // new every render + const table = useTable({ features, rowModels, columns, data }) } ``` @@ -189,11 +189,11 @@ Correct: ```tsx // Module scope — declared once. -const _features = tableFeatures({ rowSortingFeature }) -const _rowModels = { sortedRowModel: createSortedRowModel(sortFns) } +const features = tableFeatures({ rowSortingFeature }) +const rowModels = { sortedRowModel: createSortedRowModel(sortFns) } function MyTable({ data }) { - const table = useTable({ _features, _rowModels, columns, data }) + const table = useTable({ features, rowModels, columns, data }) } ``` @@ -325,7 +325,7 @@ header: ({ table }) => ( Correct: ```tsx -const table = useTable({ _features, _rowModels, columns, data }) +const table = useTable({ features, rowModels, columns, data }) // Reach for Subscribe later, scoped to actual hotspots. ``` diff --git a/packages/react-table/skills/react/table-state/SKILL.md b/packages/react-table/skills/react/table-state/SKILL.md index 3ffb6ac58b..acb670c0f1 100644 --- a/packages/react-table/skills/react/table-state/SKILL.md +++ b/packages/react-table/skills/react/table-state/SKILL.md @@ -35,7 +35,7 @@ This skill builds on `tanstack-table/state-management` and `tanstack-table/setup ## Setup -Every React v9 table follows the same shape. Define `_features`, `_rowModels`, and `columns` at module scope so their references are stable, then call `useTable` and render with ``. +Every React v9 table follows the same shape. Define `features`, `rowModels`, and `columns` at module scope so their references are stable, then call `useTable` and render with ``. ```tsx import { @@ -51,8 +51,8 @@ import type { ColumnDef } from '@tanstack/react-table' type Person = { firstName: string; lastName: string; age: number } // Module-scope = stable identity. Critical for re-render perf. -const _features = tableFeatures({ rowSortingFeature }) -const columnHelper = createColumnHelper() +const features = tableFeatures({ rowSortingFeature }) +const columnHelper = createColumnHelper() const columns = columnHelper.columns([ columnHelper.accessor('firstName', { header: 'First' }), @@ -63,8 +63,8 @@ const columns = columnHelper.columns([ function PeopleTable({ data }: { data: Person[] }) { const table = useTable( { - _features, - _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, data, }, @@ -110,7 +110,7 @@ The default is `(state) => state` — the component re-renders on any state chan ```tsx // Narrow selector — only re-render this component on sorting/pagination changes. -const table = useTable({ _features, _rowModels, columns, data }, (state) => ({ +const table = useTable({ features, rowModels, columns, data }, (state) => ({ sorting: state.sorting, pagination: state.pagination, })) @@ -182,8 +182,8 @@ function MyTable({ columns, data }) { const pagination = useSelector(paginationAtom) const table = useTable({ - _features, - _rowModels: { + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns), paginatedRowModel: createPaginatedRowModel(), }, @@ -199,14 +199,14 @@ Source: `examples/react/basic-external-atoms/src/main.tsx`. ### 4. `createTableHook` for reusable shared config -When you ship the same `_features` / `_rowModels` / cell components across many tables, package them with `createTableHook`. You get `useAppTable`, `createAppColumnHelper`, and `table.AppTable` / `AppHeader` / `AppCell` / `AppFooter` boundaries. +When you ship the same `features` / `rowModels` / cell components across many tables, package them with `createTableHook`. You get `useAppTable`, `createAppColumnHelper`, and `table.AppTable` / `AppHeader` / `AppCell` / `AppFooter` boundaries. ```tsx import { createTableHook } from '@tanstack/react-table' const { useAppTable, createAppColumnHelper } = createTableHook({ - _features: {}, - _rowModels: {}, + features: {}, + rowModels: {}, debugTable: true, }) @@ -267,8 +267,8 @@ Wrong: ```tsx const table = useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, atoms: { pagination: paginationAtom }, @@ -282,8 +282,8 @@ Correct: ```tsx // Pick exactly one source of truth per slice. const table = useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, atoms: { pagination: paginationAtom }, @@ -337,8 +337,8 @@ Wrong: function MyTable() { const sortingAtom = createAtom([]) // new atom every render useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, atoms: { sorting: sortingAtom }, @@ -352,8 +352,8 @@ Correct: function MyTable() { const sortingAtom = useCreateAtom([]) // stable across renders useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data, atoms: { sorting: sortingAtom }, @@ -364,19 +364,19 @@ function MyTable() { A fresh atom each render unbinds the table from the slice and resets the state to the initial value on every render. Source: `examples/react/basic-external-atoms/src/main.tsx`. -### HIGH Unstable `data` / `columns` / `_features` references +### HIGH Unstable `data` / `columns` / `features` references Wrong: ```tsx function MyTable({ rows }) { - const _features = tableFeatures({ rowSortingFeature }) // new every render + const features = tableFeatures({ rowSortingFeature }) // new every render const columns = [ /* … */ ] // new every render const table = useTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, data: rows ?? [], }) @@ -387,14 +387,14 @@ Correct: ```tsx // Module scope — declared once. -const _features = tableFeatures({ rowSortingFeature }) -const columns: ColumnDef[] = [ +const features = tableFeatures({ rowSortingFeature }) +const columns: ColumnDef[] = [ /* … */ ] function MyTable({ rows }) { const data = rows ?? EMPTY // EMPTY at module scope - const table = useTable({ _features, _rowModels: {}, columns, data }) + const table = useTable({ features, rowModels: {}, columns, data }) } ``` @@ -418,7 +418,7 @@ Correct: ```tsx // Default selector + inline rendering. Reach for Subscribe later, scoped to actual hotspots. -const table = useTable({ _features, _rowModels, columns, data }) +const table = useTable({ features, rowModels, columns, data }) ``` Subscribe and narrow selectors are for large / expensive tables where full re-renders measurably hurt. On a small table they only add complexity. diff --git a/packages/react-table/src/createTableHook.tsx b/packages/react-table/src/createTableHook.tsx index 2095137adc..4e469dd5bf 100644 --- a/packages/react-table/src/createTableHook.tsx +++ b/packages/react-table/src/createTableHook.tsx @@ -519,12 +519,12 @@ export type AppReactTable< * useCellContext, * useHeaderContext, * } = createTableHook({ - * _features: tableFeatures({ + * features: tableFeatures({ * rowPaginationFeature, * rowSortingFeature, * columnFilteringFeature, * }), - * _rowModels: { + * rowModels: { * paginatedRowModel: createPaginatedRowModel(), * sortedRowModel: createSortedRowModel(sortFns), * filteredRowModel: createFilteredRowModel(filterFns), @@ -806,7 +806,7 @@ export function createTableHook< >( tableOptions: Omit< TableOptions, - '_features' | '_rowModels' + 'features' | 'rowModels' >, selector?: (state: TableState) => TSelected, ): AppReactTable< @@ -1111,7 +1111,7 @@ export function createTableHook< } return { - appFeatures: defaultTableOptions._features as TFeatures, + appFeatures: defaultTableOptions.features as TFeatures, createAppColumnHelper, useAppTable, useTableContext, diff --git a/packages/react-table/src/useLegacyTable.ts b/packages/react-table/src/useLegacyTable.ts index 989f916624..cb32a1f8e5 100644 --- a/packages/react-table/src/useLegacyTable.ts +++ b/packages/react-table/src/useLegacyTable.ts @@ -198,57 +198,57 @@ export interface LegacyRowModelOptions { getCoreRowModel?: RowModelFactory /** * Returns the filtered row model for the table. - * @deprecated Use `_rowModels.filteredRowModel` with `createFilteredRowModel(filterFns)` instead. + * @deprecated Use `rowModels.filteredRowModel` with `createFilteredRowModel(filterFns)` instead. */ getFilteredRowModel?: RowModelFactory /** * Returns the sorted row model for the table. - * @deprecated Use `_rowModels.sortedRowModel` with `createSortedRowModel(sortFns)` instead. + * @deprecated Use `rowModels.sortedRowModel` with `createSortedRowModel(sortFns)` instead. */ getSortedRowModel?: RowModelFactory /** * Returns the paginated row model for the table. - * @deprecated Use `_rowModels.paginatedRowModel` with `createPaginatedRowModel()` instead. + * @deprecated Use `rowModels.paginatedRowModel` with `createPaginatedRowModel()` instead. */ getPaginationRowModel?: RowModelFactory /** * Returns the expanded row model for the table. - * @deprecated Use `_rowModels.expandedRowModel` with `createExpandedRowModel()` instead. + * @deprecated Use `rowModels.expandedRowModel` with `createExpandedRowModel()` instead. */ getExpandedRowModel?: RowModelFactory /** * Returns the grouped row model for the table. - * @deprecated Use `_rowModels.groupedRowModel` with `createGroupedRowModel(aggregationFns)` instead. + * @deprecated Use `rowModels.groupedRowModel` with `createGroupedRowModel(aggregationFns)` instead. */ getGroupedRowModel?: RowModelFactory /** * Returns the faceted row model for a column. - * @deprecated Use `_rowModels.facetedRowModel` with `createFacetedRowModel()` instead. + * @deprecated Use `rowModels.facetedRowModel` with `createFacetedRowModel()` instead. */ getFacetedRowModel?: FacetedRowModelFactory /** * Returns the faceted min/max values for a column. - * @deprecated Use `_rowModels.facetedMinMaxValues` with `createFacetedMinMaxValues()` instead. + * @deprecated Use `rowModels.facetedMinMaxValues` with `createFacetedMinMaxValues()` instead. */ getFacetedMinMaxValues?: FacetedMinMaxValuesFactory /** * Returns the faceted unique values for a column. - * @deprecated Use `_rowModels.facetedUniqueValues` with `createFacetedUniqueValues()` instead. + * @deprecated Use `rowModels.facetedUniqueValues` with `createFacetedUniqueValues()` instead. */ getFacetedUniqueValues?: FacetedUniqueValuesFactory /** * Additional filter functions to apply to the table. - * @deprecated Use `_rowModels.filteredRowModel` with `createFilteredRowModel(filterFns)` instead. + * @deprecated Use `rowModels.filteredRowModel` with `createFilteredRowModel(filterFns)` instead. */ filterFns?: FilterFns /** * Additional sort functions to apply to the table. - * @deprecated Use `_rowModels.sortedRowModel` with `createSortedRowModel(sortFns)` instead. + * @deprecated Use `rowModels.sortedRowModel` with `createSortedRowModel(sortFns)` instead. */ sortFns?: SortFns /** * Additional aggregation functions to apply to the table. - * @deprecated Use `_rowModels.groupedRowModel` with `createGroupedRowModel(aggregationFns)` instead. + * @deprecated Use `rowModels.groupedRowModel` with `createGroupedRowModel(aggregationFns)` instead. */ aggregationFns?: AggregationFns } @@ -256,14 +256,14 @@ export interface LegacyRowModelOptions { /** * Legacy v8-style table options that work with useLegacyTable. * - * This type omits `_features` and `_rowModels` and instead accepts the v8-style + * This type omits `features` and `rowModels` and instead accepts the v8-style * `get*RowModel` function options. * - * @deprecated This is a compatibility layer for migrating from v8. Use `useTable` with explicit `_features` and `_rowModels` instead. + * @deprecated This is a compatibility layer for migrating from v8. Use `useTable` with explicit `features` and `rowModels` instead. */ export type LegacyTableOptions = Omit< TableOptions, - '_features' | '_rowModels' + 'features' | 'rowModels' > & LegacyRowModelOptions @@ -353,19 +353,19 @@ export function legacyCreateColumnHelper() { /** * @deprecated This hook is provided as a compatibility layer for migrating from TanStack Table v8. * - * Use the new `useTable` hook instead with explicit `_features` and `_rowModels`: + * Use the new `useTable` hook instead with explicit `features` and `rowModels`: * * ```tsx * // New v9 API - * const _features = tableFeatures({ + * const features = tableFeatures({ * columnFilteringFeature, * rowSortingFeature, * rowPaginationFeature, * }) * * const table = useTable({ - * _features, - * _rowModels: { + * features, + * rowModels: { * filteredRowModel: createFilteredRowModel(filterFns), * sortedRowModel: createSortedRowModel(sortFns), * paginatedRowModel: createPaginatedRowModel(), @@ -377,7 +377,7 @@ export function legacyCreateColumnHelper() { * * Key differences from v8: * - Features are tree-shakeable - only import what you use - * - Row models are explicitly passed via `_rowModels` + * - Row models are explicitly passed via `rowModels` * - Use `table.Subscribe` for fine-grained re-renders * - State is accessed via `table.state` after selecting with the 2nd argument * @@ -402,7 +402,7 @@ export function useLegacyTable( ...restOptions } = options - const [_rowModels] = useState(() => { + const [rowModels] = useState(() => { const rowModels: CreateRowModels_All = {} // Legacy row model options are setup-only. Capture the first render's @@ -456,8 +456,8 @@ export function useLegacyTable( const table = useTable>( { ...restOptions, - _features: stockFeatures, - _rowModels, + features: stockFeatures, + rowModels, }, (state) => state, ) diff --git a/packages/react-table/src/useTable.ts b/packages/react-table/src/useTable.ts index 54e7dc606a..03e415d9d9 100644 --- a/packages/react-table/src/useTable.ts +++ b/packages/react-table/src/useTable.ts @@ -128,8 +128,8 @@ export type ReactTable< * ```tsx * const table = useTable( * { - * _features, - * _rowModels: {}, + * features, + * rowModels: {}, * columns, * data, * }, @@ -150,9 +150,9 @@ export function useTable< const [table] = useState(() => { const tableInstance = constructTable({ ...tableOptions, - _features: { + features: { coreReativityFeature: reactReactivity(), - ...tableOptions._features, + ...tableOptions.features, }, }) as unknown as ReactTable diff --git a/packages/solid-table-devtools/skills/solid/compose-with-tanstack-devtools/SKILL.md b/packages/solid-table-devtools/skills/solid/compose-with-tanstack-devtools/SKILL.md index 243b3c4316..ff6afea438 100644 --- a/packages/solid-table-devtools/skills/solid/compose-with-tanstack-devtools/SKILL.md +++ b/packages/solid-table-devtools/skills/solid/compose-with-tanstack-devtools/SKILL.md @@ -47,8 +47,8 @@ import { function UsersScreen() { const table = createTable({ - _features, - _rowModels, + features, + rowModels, key: 'users-table', columns, data, diff --git a/packages/solid-table/skills/solid/client-to-server/SKILL.md b/packages/solid-table/skills/solid/client-to-server/SKILL.md index 4b2c0d29cb..76e69d4c56 100644 --- a/packages/solid-table/skills/solid/client-to-server/SKILL.md +++ b/packages/solid-table/skills/solid/client-to-server/SKILL.md @@ -69,7 +69,7 @@ import { import { createAtom, useSelector } from '@tanstack/solid-store' import { createResource } from 'solid-js' -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, rowSortingFeature, columnFilteringFeature, @@ -104,8 +104,8 @@ function ServerTable() { ) const table = createTable({ - _features, - _rowModels: {}, // <- no factories needed for the manual slices + features, + rowModels: {}, // <- no factories needed for the manual slices columns, get data() { return resource()?.rows ?? [] @@ -145,8 +145,8 @@ const [sorting, setSorting] = createSignal([]) const [filters, setFilters] = createSignal([]) const table = createTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, get data() { return resource()?.rows ?? [] @@ -216,7 +216,7 @@ silently ignored. Pick one ownership model per slice. ### HIGH — kept the client row-model factory after going manual -If you flipped `manualSorting: true`, keeping `_rowModels.sortedRowModel: createSortedRowModel(sortFns)` does no harm but is dead weight in the bundle and confusing to readers. Remove it. +If you flipped `manualSorting: true`, keeping `rowModels.sortedRowModel: createSortedRowModel(sortFns)` does no harm but is dead weight in the bundle and confusing to readers. Remove it. ### MEDIUM — `data: data()` instead of `get data()` diff --git a/packages/solid-table/skills/solid/compose-with-tanstack-form/SKILL.md b/packages/solid-table/skills/solid/compose-with-tanstack-form/SKILL.md index 46f0c0b908..5e752d23c7 100644 --- a/packages/solid-table/skills/solid/compose-with-tanstack-form/SKILL.md +++ b/packages/solid-table/skills/solid/compose-with-tanstack-form/SKILL.md @@ -137,12 +137,12 @@ import { z } from 'zod' import { createMemo, For } from 'solid-js' import { useAppForm } from './form' -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, columnFilteringFeature, }) -const columnHelper = createColumnHelper() +const columnHelper = createColumnHelper() function App() { const form = useAppForm(() => ({ @@ -188,8 +188,8 @@ function App() { ) const table = createTable({ - _features, - _rowModels: { + features, + rowModels: { filteredRowModel: createFilteredRowModel(filterFns), paginatedRowModel: createPaginatedRowModel(), }, @@ -272,7 +272,7 @@ new row automatically. If you want "delete selected rows": -1. Register `rowSelectionFeature` in `_features`. +1. Register `rowSelectionFeature` in `features`. 2. Add a checkbox display column. Use `row.getIsSelected()` / `row.getToggleSelectedHandler()`. 3. On delete: read `table.getSelectedRowModel().rows`, find each `row.index`, call `form.removeFieldValue('data', index)` (highest index first to avoid shifting). diff --git a/packages/solid-table/skills/solid/compose-with-tanstack-pacer/SKILL.md b/packages/solid-table/skills/solid/compose-with-tanstack-pacer/SKILL.md index 7d1f47597f..717acc7cf0 100644 --- a/packages/solid-table/skills/solid/compose-with-tanstack-pacer/SKILL.md +++ b/packages/solid-table/skills/solid/compose-with-tanstack-pacer/SKILL.md @@ -51,11 +51,11 @@ import { import { useDebouncedCallback } from '@tanstack/solid-pacer/debouncer' import { For, createSignal } from 'solid-js' -const _features = tableFeatures({ columnFilteringFeature }) -const columnHelper = createColumnHelper() +const features = tableFeatures({ columnFilteringFeature }) +const columnHelper = createColumnHelper() function FirstNameFilter(props: { - column: Column + column: Column }) { // Local input value updates immediately (good UX). const [text, setText] = createSignal('') @@ -91,8 +91,8 @@ function App() { const [data] = createSignal(makeData(10_000)) const table = createTable({ - _features, - _rowModels: { filteredRowModel: createFilteredRowModel(filterFns) }, + features, + rowModels: { filteredRowModel: createFilteredRowModel(filterFns) }, columns, get data() { return data() @@ -139,8 +139,8 @@ columns this can cause noticeable lag on slower machines. import { useThrottledCallback } from '@tanstack/solid-pacer/throttler' const table = createTable({ - _features: tableFeatures({ columnSizingFeature, columnResizingFeature }), - _rowModels: {}, + features: tableFeatures({ columnSizingFeature, columnResizingFeature }), + rowModels: {}, columns, get data() { return data() diff --git a/packages/solid-table/skills/solid/compose-with-tanstack-query/SKILL.md b/packages/solid-table/skills/solid/compose-with-tanstack-query/SKILL.md index 3043569d19..6f0f965738 100644 --- a/packages/solid-table/skills/solid/compose-with-tanstack-query/SKILL.md +++ b/packages/solid-table/skills/solid/compose-with-tanstack-query/SKILL.md @@ -50,8 +50,8 @@ import { } from '@tanstack/solid-table' import { For } from 'solid-js' -const _features = tableFeatures({ rowPaginationFeature }) -const columnHelper = createColumnHelper() +const features = tableFeatures({ rowPaginationFeature }) +const columnHelper = createColumnHelper() const columns = columnHelper.columns([ columnHelper.accessor('firstName', { header: 'First Name' }), columnHelper.accessor('lastName', { header: 'Last Name' }), @@ -77,8 +77,8 @@ function App() { // 2. Hand server data + rowCount to the table via getters. const table = createTable({ - _features, - _rowModels: {}, // no client-side paginatedRowModel; server already paged + features, + rowModels: {}, // no client-side paginatedRowModel; server already paged columns, get data() { return dataQuery.data?.rows ?? defaultRows @@ -152,7 +152,7 @@ function App() { - **`placeholderData: keepPreviousData`** — without this, switching pages shows the loading state with zero rows, then "pops" to the next page. With it, the previous page stays visible until the new page resolves. - **`atoms.pagination`** — sharing the atom between the query (read) and the table (read+write) is what wires the two together. No event bus, no `useEffect`. - **`manualPagination: true`** — tells the table not to slice rows. The server already did. -- **No `paginatedRowModel`** — no factory needed for the manual slice. `_rowModels: {}` is correct. +- **No `paginatedRowModel`** — no factory needed for the manual slice. `rowModels: {}` is correct. - **`rowCount`** — necessary so `table.getPageCount()`, `getCanNextPage()`, and `lastPage()` know the true total. Without it the table only sees one page of rows. ## Adding sorting and filtering @@ -187,12 +187,12 @@ const dataQuery = useQuery(() => ({ })) const table = createTable({ - _features: tableFeatures({ + features: tableFeatures({ rowPaginationFeature, rowSortingFeature, columnFilteringFeature, }), - _rowModels: {}, + rowModels: {}, columns, get data() { return dataQuery.data?.rows ?? defaultRows diff --git a/packages/solid-table/skills/solid/compose-with-tanstack-store/SKILL.md b/packages/solid-table/skills/solid/compose-with-tanstack-store/SKILL.md index 8796fb3716..735deb7ae8 100644 --- a/packages/solid-table/skills/solid/compose-with-tanstack-store/SKILL.md +++ b/packages/solid-table/skills/solid/compose-with-tanstack-store/SKILL.md @@ -131,8 +131,8 @@ const pagination = useSelector(paginationAtom) const sorting = useSelector(sortingAtom) const table = createTable({ - _features, - _rowModels: { + features, + rowModels: { /* ... */ }, columns, @@ -189,8 +189,8 @@ export function PageStatus() { // UsersTable.tsx const table = createTable({ - _features, - _rowModels, + features, + rowModels, columns, get data() { return data() diff --git a/packages/solid-table/skills/solid/compose-with-tanstack-virtual/SKILL.md b/packages/solid-table/skills/solid/compose-with-tanstack-virtual/SKILL.md index 705f29eeb4..31d6353b5a 100644 --- a/packages/solid-table/skills/solid/compose-with-tanstack-virtual/SKILL.md +++ b/packages/solid-table/skills/solid/compose-with-tanstack-virtual/SKILL.md @@ -54,14 +54,14 @@ import { } from '@tanstack/solid-virtual' import { For, createSignal } from 'solid-js' -const _features = tableFeatures({ columnSizingFeature, rowSortingFeature }) +const features = tableFeatures({ columnSizingFeature, rowSortingFeature }) function App() { const [data] = createSignal(makeData(200_000)) const table = createTable({ - _features, - _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, get data() { return data() @@ -73,7 +73,7 @@ function App() { // Keep the virtualizer + scroll container ref in the SAME component. function VirtualizedTable(props: { - table: SolidTable + table: SolidTable }) { let tableContainerRef: HTMLDivElement | undefined @@ -153,10 +153,10 @@ function VirtualizedTable(props: { } function TableBodyRow(props: { - row: Row + row: Row virtualRow: VirtualItem rowVirtualizer: Virtualizer - table: SolidTable + table: SolidTable }) { return ( End-to-end first table with `@tanstack/solid-table` v9. Install, declare - `_features` via `tableFeatures()`, declare `_rowModels` with the matching + `features` via `tableFeatures()`, declare `rowModels` with the matching factories (e.g. `createSortedRowModel(sortFns)`), create a column helper - with `createColumnHelper()`, build the table with + with `createColumnHelper()`, build the table with `createTable(options)` using reactive `get data() {...}` getters, and render rows via `FlexRender` (or `table.FlexRender`). type: lifecycle @@ -42,7 +42,7 @@ npm install @tanstack/solid-table the Solid-specific `createTable`, `FlexRender`, and `createTableHook`. You should not install `@tanstack/table-core` separately. -## 2. Declare features (`_features`) +## 2. Declare features (`features`) v9 is explicit about what a table uses. Only registered features expose APIs and state slices. This is what makes the bundle tree-shake. @@ -55,7 +55,7 @@ import { columnFilteringFeature, } from '@tanstack/solid-table' -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, rowSortingFeature, columnFilteringFeature, @@ -66,7 +66,7 @@ const _features = tableFeatures({ object used everywhere (column helper, table options, etc.). Use it even for a no-feature table: `tableFeatures({})`. -## 3. Declare row-model factories (`_rowModels`) +## 3. Declare row-model factories (`rowModels`) Each non-core row-model feature needs its factory called and registered. The core row model is included by default. @@ -80,7 +80,7 @@ import { filterFns, } from '@tanstack/solid-table' -const _rowModels = { +const rowModels = { paginatedRowModel: createPaginatedRowModel(), sortedRowModel: createSortedRowModel(sortFns), filteredRowModel: createFilteredRowModel(filterFns), @@ -93,7 +93,7 @@ object like `{ alphanumeric: sortFns.alphanumeric }`. ## 4. Define columns -`createColumnHelper` takes **both** generics: `typeof _features` first, then +`createColumnHelper` takes **both** generics: `typeof features` first, then `TData`. (This is the v9 ordering. v8 only had `TData`.) ```tsx @@ -101,7 +101,7 @@ import { createColumnHelper } from '@tanstack/solid-table' type Person = { firstName: string; lastName: string; age: number } -const columnHelper = createColumnHelper() +const columnHelper = createColumnHelper() const columns = columnHelper.columns([ columnHelper.accessor('firstName', { @@ -132,8 +132,8 @@ function App() { ]) const table = createTable({ - _features, - _rowModels, + features, + rowModels, columns, get data() { return data() // reactive getter @@ -190,8 +190,8 @@ once with `createTableHook`: import { createTableHook } from '@tanstack/solid-table' const { createAppTable, createAppColumnHelper } = createTableHook({ - _features: tableFeatures({}), - _rowModels: {}, + features: tableFeatures({}), + rowModels: {}, }) const columnHelper = createAppColumnHelper() @@ -216,12 +216,12 @@ function App(props: { data: Array }) { ```tsx // ❌ Reads once at construction — table never updates when data() changes -createTable({ _features, _rowModels: {}, columns, data: data() }) +createTable({ features, rowModels: {}, columns, data: data() }) // ✅ Tracked createTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, get data() { return data() @@ -246,7 +246,7 @@ table.state().pagination ### Missing feature → missing API -If you write `table.setSorting(...)` without `rowSortingFeature` in `_features`, +If you write `table.setSorting(...)` without `rowSortingFeature` in `features`, TS errors and the method is undefined at runtime. The fix is registration, not a cast. @@ -264,6 +264,6 @@ rolling your own state update. ### Hallucinated names from older versions v9 is `createTable`, not `createSolidTable` (that was v8). Row models go under -`_rowModels`, not top-level `getCoreRowModel` / `getSortedRowModel` options. -`createColumnHelper` takes `` (two generics, features +`rowModels`, not top-level `getCoreRowModel` / `getSortedRowModel` options. +`createColumnHelper` takes `` (two generics, features first). diff --git a/packages/solid-table/skills/solid/migrate-v8-to-v9/SKILL.md b/packages/solid-table/skills/solid/migrate-v8-to-v9/SKILL.md index 00eff01eff..e6a2f89624 100644 --- a/packages/solid-table/skills/solid/migrate-v8-to-v9/SKILL.md +++ b/packages/solid-table/skills/solid/migrate-v8-to-v9/SKILL.md @@ -3,8 +3,8 @@ name: solid/migrate-v8-to-v9 description: > Mechanical breaking-change migration from `@tanstack/solid-table` v8 to v9. Renames (`createSolidTable` → `createTable`, `getCoreRowModel`/`getSortedRowModel`/... - → `_rowModels` + factories), new required `_features` registration via - `tableFeatures()`, two-generic `createColumnHelper`, + → `rowModels` + factories), new required `features` registration via + `tableFeatures()`, two-generic `createColumnHelper`, the v9 atom state model, and the lack of a `/legacy` entrypoint for Solid (full rewrite, no `useLegacyTable`). type: lifecycle @@ -31,30 +31,30 @@ direct rewrite. Plan to do it incrementally per table, not per file. ## What changed (high-level) 1. **Adapter API renamed.** `createSolidTable(...)` → `createTable(...)`. -2. **Features must be registered.** v9 introduced `_features` via `tableFeatures({...})`. Without it, feature APIs and state slices don't exist (TS error + runtime undefined). -3. **Row models moved to `_rowModels`.** No more top-level `getCoreRowModel: getCoreRowModel()` options; instead `_rowModels: { paginatedRowModel: createPaginatedRowModel(), ... }`. +2. **Features must be registered.** v9 introduced `features` via `tableFeatures({...})`. Without it, feature APIs and state slices don't exist (TS error + runtime undefined). +3. **Row models moved to `rowModels`.** No more top-level `getCoreRowModel: getCoreRowModel()` options; instead `rowModels: { paginatedRowModel: createPaginatedRowModel(), ... }`. 4. **State is atom-based.** Powered by TanStack Store. The classic `state`+`on*Change` pattern still works for compatibility, but `atoms` is the new recommended hand-off for per-slice external ownership. -5. **`createColumnHelper` takes two generics.** `createColumnHelper()` (features first). +5. **`createColumnHelper` takes two generics.** `createColumnHelper()` (features first). 6. **Some method/option renames.** Most notably `sortingFn` → `sortFn`; the `*Fns` registries (`sortFns`, `filterFns`, `aggregationFns`) are now passed to row-model factories. 7. **No `onStateChange` top-level callback.** Use per-slice `on[State]Change` paired with `state.`, or use `atoms`. ## Rename map -| v8 (Solid) | v9 (Solid) | -| -------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | -| `createSolidTable(options)` | `createTable(options, selector?)` | -| `getCoreRowModel: getCoreRowModel()` | (core row model included by default; pass `_rowModels: {}`) | -| `getSortedRowModel: getSortedRowModel()` | `_rowModels: { sortedRowModel: createSortedRowModel(sortFns) }` + register `rowSortingFeature` | -| `getFilteredRowModel: getFilteredRowModel()` | `_rowModels: { filteredRowModel: createFilteredRowModel(filterFns) }` + register `columnFilteringFeature` | -| `getPaginationRowModel: getPaginationRowModel()` | `_rowModels: { paginatedRowModel: createPaginatedRowModel() }` + register `rowPaginationFeature` | -| `getGroupedRowModel: getGroupedRowModel()` | `_rowModels: { groupedRowModel: createGroupedRowModel(aggregationFns) }` + register `columnGroupingFeature` | -| `getExpandedRowModel: getExpandedRowModel()` | `_rowModels: { expandedRowModel: createExpandedRowModel() }` + register `rowExpandingFeature` | -| `getFacetedRowModel` / `getFacetedUniqueValues` / `getFacetedMinMaxValues` | `_rowModels: { facetedRowModel, facetedUniqueValues, facetedMinMaxValues }` + faceting features | -| `createColumnHelper()` | `createColumnHelper()` | -| `sortingFn: 'alphanumeric'` on a column | `sortFn: 'alphanumeric'` on a column | -| `onStateChange` (whole-state) | (gone — use per-slice `on*Change` or `atoms`) | -| `state: { ... }` + `onStateChange` | `state: { ... }` + `on[State]Change`, OR `atoms: { ... }` | -| (no atoms) | `atoms: { sorting: someAtom, pagination: someAtom, ... }` | +| v8 (Solid) | v9 (Solid) | +| -------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | +| `createSolidTable(options)` | `createTable(options, selector?)` | +| `getCoreRowModel: getCoreRowModel()` | (core row model included by default; pass `rowModels: {}`) | +| `getSortedRowModel: getSortedRowModel()` | `rowModels: { sortedRowModel: createSortedRowModel(sortFns) }` + register `rowSortingFeature` | +| `getFilteredRowModel: getFilteredRowModel()` | `rowModels: { filteredRowModel: createFilteredRowModel(filterFns) }` + register `columnFilteringFeature` | +| `getPaginationRowModel: getPaginationRowModel()` | `rowModels: { paginatedRowModel: createPaginatedRowModel() }` + register `rowPaginationFeature` | +| `getGroupedRowModel: getGroupedRowModel()` | `rowModels: { groupedRowModel: createGroupedRowModel(aggregationFns) }` + register `columnGroupingFeature` | +| `getExpandedRowModel: getExpandedRowModel()` | `rowModels: { expandedRowModel: createExpandedRowModel() }` + register `rowExpandingFeature` | +| `getFacetedRowModel` / `getFacetedUniqueValues` / `getFacetedMinMaxValues` | `rowModels: { facetedRowModel, facetedUniqueValues, facetedMinMaxValues }` + faceting features | +| `createColumnHelper()` | `createColumnHelper()` | +| `sortingFn: 'alphanumeric'` on a column | `sortFn: 'alphanumeric'` on a column | +| `onStateChange` (whole-state) | (gone — use per-slice `on*Change` or `atoms`) | +| `state: { ... }` + `onStateChange` | `state: { ... }` + `on[State]Change`, OR `atoms: { ... }` | +| (no atoms) | `atoms: { sorting: someAtom, pagination: someAtom, ... }` | ## Before → after @@ -119,12 +119,12 @@ import { } from '@tanstack/solid-table' import { For, createSignal } from 'solid-js' -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, rowSortingFeature, }) -const columnHelper = createColumnHelper() +const columnHelper = createColumnHelper() const columns = columnHelper.columns([ columnHelper.accessor('firstName', { header: 'First Name' }), @@ -135,8 +135,8 @@ function App(props: { data: Person[] }) { const [sorting, setSorting] = createSignal([]) const table = createTable({ - _features, - _rowModels: { + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns), paginatedRowModel: createPaginatedRowModel(), }, @@ -197,8 +197,8 @@ table.state().sorting const sortingAtom = createAtom([]) createTable({ - _features, - _rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns) }, columns, get data() { return data() @@ -236,21 +236,21 @@ On columns, the option name is now `sortFn`, `filterFn`, `aggregationFn` ## Failure modes -### CRITICAL — `_features` missing → API gone +### CRITICAL — `features` missing → API gone The single biggest v8→v9 trap. `table.setSorting` won't exist unless -`rowSortingFeature` is in `_features`. Likewise for every other feature. v8 had +`rowSortingFeature` is in `features`. Likewise for every other feature. v8 had no such requirement. ### CRITICAL — `getCoreRowModel: getCoreRowModel()` pattern v9 has no such option. The core row model is included by default. Move every -`get*RowModel` option to a key under `_rowModels` and call the matching +`get*RowModel` option to a key under `rowModels` and call the matching `create*RowModel()` factory. Don't leave the v8 options in place. ### CRITICAL — `createColumnHelper()` missing the features generic -v8: `createColumnHelper()`. v9: `createColumnHelper()`. +v8: `createColumnHelper()`. v9: `createColumnHelper()`. Forgetting the first generic gives bad inference and broken cell typing. ### HIGH — `createSolidTable` no longer exists diff --git a/packages/solid-table/skills/solid/production-readiness/SKILL.md b/packages/solid-table/skills/solid/production-readiness/SKILL.md index 52383cf5bb..572b4eaf11 100644 --- a/packages/solid-table/skills/solid/production-readiness/SKILL.md +++ b/packages/solid-table/skills/solid/production-readiness/SKILL.md @@ -2,7 +2,7 @@ name: solid/production-readiness description: > Ship-ready optimizations for `@tanstack/solid-table` v9. Tree-shake by - registering only the `_features` you use; keep `_features`, `columns`, `data` + registering only the `features` you use; keep `features`, `columns`, `data` stable; prefer per-slice external atoms (`createAtom` + `useSelector`) and narrow selectors over `(state) => state`; leverage Solid's fine-grained reactivity (`createMemo`, JSX-level reads) so most components subscribe to @@ -30,7 +30,7 @@ A v9 table that "works in dev" can still ship slow if you copied the getting-started shape unchanged into a 10k-row scenario. Solid's fine-grained reactivity rewards a few production habits. -## 1. Tree-shake `_features` aggressively +## 1. Tree-shake `features` aggressively v9's biggest bundle win. Register only the features you use. @@ -46,7 +46,7 @@ import { columnFilteringFeature, } from '@tanstack/solid-table' -const _features = tableFeatures({ +const features = tableFeatures({ rowPaginationFeature, rowSortingFeature, columnFilteringFeature, @@ -64,25 +64,25 @@ const sortRegistry = { createSortedRowModel(sortRegistry) ``` -## 2. Keep `_features`, `data`, `columns` stable +## 2. Keep `features`, `data`, `columns` stable The Solid signal model already protects you from React-style re-creation, but two patterns still break things: -- **Re-creating `_features` per render.** Module-scope it. Don't call +- **Re-creating `features` per render.** Module-scope it. Don't call `tableFeatures({...})` inside a component. - **Returning a fresh `[]` on every read.** When `data` is unloaded (`resource()?.rows ?? []`), the fallback `[]` should be a module-scope constant so identity is stable. ```tsx -const _features = tableFeatures({ rowPaginationFeature, rowSortingFeature }) +const features = tableFeatures({ rowPaginationFeature, rowSortingFeature }) const EMPTY_ROWS: Array = [] function App() { const table = createTable({ - _features, // stable - _rowModels: { + features, // stable + rowModels: { /* stable factories OK module-scoped */ }, columns, // module-scope constant @@ -103,8 +103,8 @@ const columns = createMemo(() => ]), ) createTable({ - _features, - _rowModels, + features, + rowModels, get columns() { return columns() }, @@ -122,8 +122,8 @@ The default `createTable(options)` selector is identity. Anything reading ```tsx const table = createTable( { - _features, - _rowModels, + features, + rowModels, columns, get data() { return data() @@ -211,12 +211,12 @@ which is excluded from v9 alpha. ### CRITICAL — registering features you don't use Every registered feature adds state slices, derivations, and code to the -bundle. Keep `_features` minimal. +bundle. Keep `features` minimal. -### CRITICAL — recreating `_features` / `columns` / `data` identity on every render +### CRITICAL — recreating `features` / `columns` / `data` identity on every render Solid's reactivity assumes stable references for options that are not behind -getters. `_features` and `columns` should be module-scoped; reactive options +getters. `features` and `columns` should be module-scoped; reactive options should use getters; fallbacks should be module-scope constants. ### HIGH — `(state) => state` default selector in a frequently-reading component diff --git a/packages/solid-table/skills/solid/table-state/SKILL.md b/packages/solid-table/skills/solid/table-state/SKILL.md index bf1dd15f0b..bb9a933bf5 100644 --- a/packages/solid-table/skills/solid/table-state/SKILL.md +++ b/packages/solid-table/skills/solid/table-state/SKILL.md @@ -42,8 +42,8 @@ A `createTable(...)` call produces a `SolidTable` with several state surfaces: - `table.store` — flat readonly TanStack Store snapshot for explicit subscriptions. Prefer `table.state()` or `table.atoms..get()` in JSX. - `table.state()` — **a Solid accessor**, not a value. Returns the result of the selector passed as the second argument to `createTable`. Default selector is identity. -State slices only exist for features registered through `_features`. If -`rowSortingFeature` is not in `_features`, then `table.atoms.sorting`, +State slices only exist for features registered through `features`. If +`rowSortingFeature` is not in `features`, then `table.atoms.sorting`, `table.state().sorting`, and `state.sorting` are all absent (TS error + missing at runtime). ## Creating a table — native signals @@ -55,14 +55,14 @@ the table tracks the upstream signal. import { createTable, tableFeatures, type ColumnDef } from '@tanstack/solid-table' import { createSignal, For } from 'solid-js' -const _features = tableFeatures({}) +const features = tableFeatures({}) function App() { const [data, setData] = createSignal>([]) const table = createTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, // Reactive getter — required so the table re-derives when data() changes. get data() { @@ -97,8 +97,8 @@ Pass a selector to narrow what `table.state()` returns: ```tsx const table = createTable( { - _features, - _rowModels: {}, + features, + rowModels: {}, columns, get data() { return data() @@ -194,8 +194,8 @@ const [pagination, setPagination] = createSignal({ }) const table = createTable({ - _features, - _rowModels: { + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns), paginatedRowModel: createPaginatedRowModel(), }, @@ -232,8 +232,8 @@ const sortingAtom = createAtom([]) const pagination = useSelector(paginationAtom) // Accessor const table = createTable({ - _features, - _rowModels: { + features, + rowModels: { sortedRowModel: createSortedRowModel(sortFns), paginatedRowModel: createPaginatedRowModel(), }, @@ -290,7 +290,7 @@ column-grouping feature is registered. ## `createTableHook` — app-level table conventions -When multiple tables share `_features`, `_rowModels`, default options, and +When multiple tables share `features`, `rowModels`, default options, and component conventions, use `createTableHook` to register them once. ```tsx @@ -308,8 +308,8 @@ const { useCellContext, useHeaderContext, } = createTableHook({ - _features: tableFeatures({ rowPaginationFeature }), - _rowModels: { paginatedRowModel: createPaginatedRowModel() }, + features: tableFeatures({ rowPaginationFeature }), + rowModels: { paginatedRowModel: createPaginatedRowModel() }, tableComponents: { PaginationControls }, cellComponents: { TextCell, NumberCell }, headerComponents: { SortIndicator }, @@ -410,7 +410,7 @@ patterns will write `table.state.sorting` and get `undefined`. Always call it: ### CRITICAL — feature not registered → API missing If you reach for `table.atoms.sorting`, `table.setSorting`, `column.getCanSort`, -etc., the matching feature (`rowSortingFeature`) must be in `_features`. +etc., the matching feature (`rowSortingFeature`) must be in `features`. Otherwise TS errors and runtime `undefined`. v9 features are explicit. ### CRITICAL — reactive `data` without a getter @@ -423,4 +423,4 @@ tracks. The same applies to any reactive option (`columns` when computed, There is no `createSolidTable` (v8 name). The Solid v9 API is `createTable`. There is no `getCoreRowModel`/`getSortedRowModel` factory option pattern — pass -row models under `_rowModels` (e.g. `_rowModels: { sortedRowModel: createSortedRowModel(sortFns) }`). +row models under `rowModels` (e.g. `rowModels: { sortedRowModel: createSortedRowModel(sortFns) }`). diff --git a/packages/solid-table/src/createTable.ts b/packages/solid-table/src/createTable.ts index b6d452a7c4..570aa1370a 100644 --- a/packages/solid-table/src/createTable.ts +++ b/packages/solid-table/src/createTable.ts @@ -102,8 +102,8 @@ export type SolidTable< * ```tsx * const table = createTable( * { - * _features, - * _rowModels: {}, + * features, + * rowModels: {}, * columns, * data, * }, @@ -125,9 +125,9 @@ export function createTable< const reactivity = solidReactivity(owner) const mergedOptions = mergeProps(tableOptions, { - _features: { + features: { coreReativityFeature: reactivity, - ...tableOptions._features, + ...tableOptions.features, }, }) as any diff --git a/packages/solid-table/src/createTableHook.tsx b/packages/solid-table/src/createTableHook.tsx index 8747fb7a57..53187d8b8e 100644 --- a/packages/solid-table/src/createTableHook.tsx +++ b/packages/solid-table/src/createTableHook.tsx @@ -532,12 +532,12 @@ export type AppSolidTable< * useCellContext, * useHeaderContext, * } = createTableHook({ - * _features: tableFeatures({ + * features: tableFeatures({ * rowPaginationFeature, * rowSortingFeature, * columnFilteringFeature, * }), - * _rowModels: { + * rowModels: { * paginatedRowModel: createPaginatedRowModel(), * sortedRowModel: createSortedRowModel(sortFns), * filteredRowModel: createFilteredRowModel(filterFns), @@ -826,7 +826,7 @@ export function createTableHook< >( tableOptions: Omit< TableOptions, - '_features' | '_rowModels' + 'features' | 'rowModels' >, selector?: (state: TableState) => TSelected, ): AppSolidTable< @@ -1085,7 +1085,7 @@ export function createTableHook< } return { - appFeatures: defaultTableOptions._features as TFeatures, + appFeatures: defaultTableOptions.features as TFeatures, createAppColumnHelper, createAppTable: createAppTable, useTableContext, diff --git a/packages/svelte-table/skills/svelte/client-to-server/SKILL.md b/packages/svelte-table/skills/svelte/client-to-server/SKILL.md index acc3a35521..f6ea93f02c 100644 --- a/packages/svelte-table/skills/svelte/client-to-server/SKILL.md +++ b/packages/svelte-table/skills/svelte/client-to-server/SKILL.md @@ -3,7 +3,7 @@ name: svelte/client-to-server description: > Convert a client-side Svelte table to server-side (manual) modes. Toggle `manualPagination`, `manualSorting`, `manualFiltering`, `manualGrouping`, `manualExpanding` for whatever the server - owns, drop the matching `_rowModels` factories and `_features` you no longer need, supply + owns, drop the matching `rowModels` factories and `features` you no longer need, supply `rowCount` for the pager, then drive the request from `table.atoms.pagination` / `table.atoms.sorting` / etc. (or external atoms you own) — using rune-aware getters (`get data()`, `get rowCount()`) so the table re-syncs in `$effect.pre`. Svelte 5+ only. @@ -102,7 +102,7 @@ const filters = useSelector(filtersAtom) tableFeatures, } from '@tanstack/svelte-table' - const _features = tableFeatures({ + const features = tableFeatures({ columnFilteringFeature, rowPaginationFeature, rowSortingFeature, @@ -110,8 +110,8 @@ const filters = useSelector(filtersAtom) // No row-model factories for these — server owns them. const table = createTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, get data() { return query.data?.rows ?? [] @@ -192,12 +192,12 @@ client. ```ts const table = createTable({ - _features: tableFeatures({ + features: tableFeatures({ columnFilteringFeature, rowPaginationFeature, rowSortingFeature, }), - _rowModels: { + rowModels: { filteredRowModel: createFilteredRowModel(filterFns), // client filters the page sortedRowModel: createSortedRowModel(sortFns), // client sorts the page }, diff --git a/packages/svelte-table/skills/svelte/compose-with-tanstack-form/SKILL.md b/packages/svelte-table/skills/svelte/compose-with-tanstack-form/SKILL.md index e05f38ee1a..7b6d3fbc8c 100644 --- a/packages/svelte-table/skills/svelte/compose-with-tanstack-form/SKILL.md +++ b/packages/svelte-table/skills/svelte/compose-with-tanstack-form/SKILL.md @@ -113,12 +113,12 @@ Each cell type is a small Svelte component that knows which row + field it edits import SelectFieldCell from './SelectFieldCell.svelte' import { makeData, type Person } from './makeData' - const _features = tableFeatures({ + const features = tableFeatures({ rowPaginationFeature, columnFilteringFeature, }) - const columnHelper = createColumnHelper() + const columnHelper = createColumnHelper() const personSchema = z.object({ firstName: z.string().min(1), @@ -169,8 +169,8 @@ Each cell type is a small Svelte component that knows which row + field it edits ]) const table = createTable({ - _features, - _rowModels: { + features, + rowModels: { filteredRowModel: createFilteredRowModel(filterFns), paginatedRowModel: createPaginatedRowModel(), }, diff --git a/packages/svelte-table/skills/svelte/compose-with-tanstack-pacer/SKILL.md b/packages/svelte-table/skills/svelte/compose-with-tanstack-pacer/SKILL.md index a1bfaaad58..7abe68b55f 100644 --- a/packages/svelte-table/skills/svelte/compose-with-tanstack-pacer/SKILL.md +++ b/packages/svelte-table/skills/svelte/compose-with-tanstack-pacer/SKILL.md @@ -45,7 +45,7 @@ storms. import { createDebouncer } from '@tanstack/svelte-pacer/debouncer' import type { Column } from '@tanstack/svelte-table' - type Props = { column: Column } + type Props = { column: Column } let { column }: Props = $props() let localValue = $state((column.getFilterValue() as string) ?? '') diff --git a/packages/svelte-table/skills/svelte/compose-with-tanstack-query/SKILL.md b/packages/svelte-table/skills/svelte/compose-with-tanstack-query/SKILL.md index 65eb77b463..04f398b825 100644 --- a/packages/svelte-table/skills/svelte/compose-with-tanstack-query/SKILL.md +++ b/packages/svelte-table/skills/svelte/compose-with-tanstack-query/SKILL.md @@ -43,7 +43,7 @@ the affected pipeline stages, pipe the result back through reactive getters. type PaginationState, } from '@tanstack/svelte-table' - const _features = tableFeatures({ rowPaginationFeature }) + const features = tableFeatures({ rowPaginationFeature }) let pagination: PaginationState = $state({ pageIndex: 0, pageSize: 10 }) @@ -57,8 +57,8 @@ the affected pipeline stages, pipe the result back through reactive getters. })) const table = createTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, get data() { return dataQuery.data?.rows ?? [] @@ -114,8 +114,8 @@ const dataQuery = createQuery(() => ({ })) const table = createTable({ - _features, - _rowModels: {}, + features, + rowModels: {}, columns, get data() { return dataQuery.data?.rows ?? [] @@ -147,12 +147,12 @@ const dataQuery = createQuery(() => ({ })) const table = createTable({ - _features: tableFeatures({ + features: tableFeatures({ rowPaginationFeature, rowSortingFeature, columnFilteringFeature, }), - _rowModels: {}, + rowModels: {}, columns, get data() { return dataQuery.data?.rows ?? [] diff --git a/packages/svelte-table/skills/svelte/compose-with-tanstack-store/SKILL.md b/packages/svelte-table/skills/svelte/compose-with-tanstack-store/SKILL.md index 6a353ea38d..c81c6bf13f 100644 --- a/packages/svelte-table/skills/svelte/compose-with-tanstack-store/SKILL.md +++ b/packages/svelte-table/skills/svelte/compose-with-tanstack-store/SKILL.md @@ -82,8 +82,8 @@ The second argument to `createTable` is a TanStack Store selector. The result is ``` -Declare `_features`, `columnHelper`, and `columns` at **module scope** (top of file, outside +Declare `features`, `columnHelper`, and `columns` at **module scope** (top of file, outside `