diff --git a/examples/angular/basic-app-table/package.json b/examples/angular/basic-app-table/package.json index 0d5b547289..5778cd7f3e 100644 --- a/examples/angular/basic-app-table/package.json +++ b/examples/angular/basic-app-table/package.json @@ -18,8 +18,8 @@ "@angular/platform-browser": "^22.0.0", "@faker-js/faker": "^10.4.0", "@tanstack/angular-devtools": "^0.0.4", - "@tanstack/angular-table": "^9.0.0-beta.12", - "@tanstack/angular-table-devtools": "^9.0.0-beta.12", + "@tanstack/angular-table": "^9.0.0-beta.15", + "@tanstack/angular-table-devtools": "^9.0.0-beta.15", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, diff --git a/examples/angular/basic-external-atoms/package.json b/examples/angular/basic-external-atoms/package.json index ab7057c855..419820c9d4 100644 --- a/examples/angular/basic-external-atoms/package.json +++ b/examples/angular/basic-external-atoms/package.json @@ -19,8 +19,8 @@ "@faker-js/faker": "^10.4.0", "@tanstack/angular-devtools": "^0.0.4", "@tanstack/angular-store": "^0.11.0", - "@tanstack/angular-table": "^9.0.0-beta.12", - "@tanstack/angular-table-devtools": "^9.0.0-beta.12", + "@tanstack/angular-table": "^9.0.0-beta.15", + "@tanstack/angular-table-devtools": "^9.0.0-beta.15", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, diff --git a/examples/angular/basic-external-state/package.json b/examples/angular/basic-external-state/package.json index b1cf7f30fb..cd56d3291a 100644 --- a/examples/angular/basic-external-state/package.json +++ b/examples/angular/basic-external-state/package.json @@ -19,8 +19,8 @@ "@faker-js/faker": "^10.4.0", "@tanstack/angular-devtools": "^0.0.4", "@tanstack/angular-store": "^0.11.0", - "@tanstack/angular-table": "^9.0.0-beta.12", - "@tanstack/angular-table-devtools": "^9.0.0-beta.12", + "@tanstack/angular-table": "^9.0.0-beta.15", + "@tanstack/angular-table-devtools": "^9.0.0-beta.15", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, diff --git a/examples/angular/basic-inject-table/package.json b/examples/angular/basic-inject-table/package.json index 77174e2ea5..a0fd6d1b37 100644 --- a/examples/angular/basic-inject-table/package.json +++ b/examples/angular/basic-inject-table/package.json @@ -19,8 +19,8 @@ "@angular/router": "^22.0.0", "@faker-js/faker": "^10.4.0", "@tanstack/angular-devtools": "^0.0.4", - "@tanstack/angular-table": "^9.0.0-beta.12", - "@tanstack/angular-table-devtools": "^9.0.0-beta.12", + "@tanstack/angular-table": "^9.0.0-beta.15", + "@tanstack/angular-table-devtools": "^9.0.0-beta.15", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, diff --git a/examples/angular/column-groups/package.json b/examples/angular/column-groups/package.json index 290bb80dbf..bdc12b0852 100644 --- a/examples/angular/column-groups/package.json +++ b/examples/angular/column-groups/package.json @@ -18,7 +18,7 @@ "@angular/platform-browser": "^22.0.0", "@angular/router": "^22.0.0", "@faker-js/faker": "^10.4.0", - "@tanstack/angular-table": "^9.0.0-beta.12", + "@tanstack/angular-table": "^9.0.0-beta.15", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, diff --git a/examples/angular/column-ordering/package.json b/examples/angular/column-ordering/package.json index f2e1a7084c..4cd3ae1162 100644 --- a/examples/angular/column-ordering/package.json +++ b/examples/angular/column-ordering/package.json @@ -18,7 +18,7 @@ "@angular/platform-browser": "^22.0.0", "@angular/router": "^22.0.0", "@faker-js/faker": "^10.4.0", - "@tanstack/angular-table": "^9.0.0-beta.12", + "@tanstack/angular-table": "^9.0.0-beta.15", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, diff --git a/examples/angular/column-pinning-split/package.json b/examples/angular/column-pinning-split/package.json index 29f3c02a2c..95477d4d80 100644 --- a/examples/angular/column-pinning-split/package.json +++ b/examples/angular/column-pinning-split/package.json @@ -18,7 +18,7 @@ "@angular/platform-browser": "^22.0.0", "@angular/router": "^22.0.0", "@faker-js/faker": "^10.4.0", - "@tanstack/angular-table": "^9.0.0-beta.12", + "@tanstack/angular-table": "^9.0.0-beta.15", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, diff --git a/examples/angular/column-pinning-sticky/package.json b/examples/angular/column-pinning-sticky/package.json index 957a580cfd..589a5cf08b 100644 --- a/examples/angular/column-pinning-sticky/package.json +++ b/examples/angular/column-pinning-sticky/package.json @@ -18,7 +18,7 @@ "@angular/platform-browser": "^22.0.0", "@angular/router": "^22.0.0", "@faker-js/faker": "^10.4.0", - "@tanstack/angular-table": "^9.0.0-beta.12", + "@tanstack/angular-table": "^9.0.0-beta.15", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, diff --git a/examples/angular/column-pinning/package.json b/examples/angular/column-pinning/package.json index 75f1448b74..0cec35f8a2 100644 --- a/examples/angular/column-pinning/package.json +++ b/examples/angular/column-pinning/package.json @@ -18,7 +18,7 @@ "@angular/platform-browser": "^22.0.0", "@angular/router": "^22.0.0", "@faker-js/faker": "^10.4.0", - "@tanstack/angular-table": "^9.0.0-beta.12", + "@tanstack/angular-table": "^9.0.0-beta.15", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, diff --git a/examples/angular/column-resizing-performant/package.json b/examples/angular/column-resizing-performant/package.json index eb218a46ca..029c12f05b 100644 --- a/examples/angular/column-resizing-performant/package.json +++ b/examples/angular/column-resizing-performant/package.json @@ -18,7 +18,7 @@ "@angular/platform-browser": "^22.0.0", "@angular/router": "^22.0.0", "@faker-js/faker": "^10.4.0", - "@tanstack/angular-table": "^9.0.0-beta.12", + "@tanstack/angular-table": "^9.0.0-beta.15", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, diff --git a/examples/angular/column-resizing/package.json b/examples/angular/column-resizing/package.json index 657fd40f06..abfde22914 100644 --- a/examples/angular/column-resizing/package.json +++ b/examples/angular/column-resizing/package.json @@ -18,7 +18,7 @@ "@angular/platform-browser": "^22.0.0", "@angular/router": "^22.0.0", "@faker-js/faker": "^10.4.0", - "@tanstack/angular-table": "^9.0.0-beta.12", + "@tanstack/angular-table": "^9.0.0-beta.15", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, diff --git a/examples/angular/column-sizing/package.json b/examples/angular/column-sizing/package.json index 875d2b53b2..aa44346357 100644 --- a/examples/angular/column-sizing/package.json +++ b/examples/angular/column-sizing/package.json @@ -18,7 +18,7 @@ "@angular/platform-browser": "^22.0.0", "@angular/router": "^22.0.0", "@faker-js/faker": "^10.4.0", - "@tanstack/angular-table": "^9.0.0-beta.12", + "@tanstack/angular-table": "^9.0.0-beta.15", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, diff --git a/examples/angular/column-visibility/package.json b/examples/angular/column-visibility/package.json index e7fc4e77fc..2fbbd96167 100644 --- a/examples/angular/column-visibility/package.json +++ b/examples/angular/column-visibility/package.json @@ -18,7 +18,7 @@ "@angular/platform-browser": "^22.0.0", "@angular/router": "^22.0.0", "@faker-js/faker": "^10.4.0", - "@tanstack/angular-table": "^9.0.0-beta.12", + "@tanstack/angular-table": "^9.0.0-beta.15", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, diff --git a/examples/angular/composable-tables/package.json b/examples/angular/composable-tables/package.json index 7c3629a4bc..730c59c945 100644 --- a/examples/angular/composable-tables/package.json +++ b/examples/angular/composable-tables/package.json @@ -19,8 +19,8 @@ "@angular/router": "^22.0.0", "@faker-js/faker": "^10.4.0", "@tanstack/angular-devtools": "^0.0.4", - "@tanstack/angular-table": "^9.0.0-beta.12", - "@tanstack/angular-table-devtools": "^9.0.0-beta.12", + "@tanstack/angular-table": "^9.0.0-beta.15", + "@tanstack/angular-table-devtools": "^9.0.0-beta.15", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, diff --git a/examples/angular/composable-tables/src/app/components/cell-components.ts b/examples/angular/composable-tables/src/app/components/cell-components.ts index 3cca4ec1d2..f8a4622e39 100644 --- a/examples/angular/composable-tables/src/app/components/cell-components.ts +++ b/examples/angular/composable-tables/src/app/components/cell-components.ts @@ -1,4 +1,4 @@ -import { Component, computed } from '@angular/core' +import { ChangeDetectionStrategy, Component, computed } from '@angular/core' import { injectFlexRenderContext } from '@tanstack/angular-table' import { CurrencyPipe } from '@angular/common' import { injectTableCellContext } from '../table' @@ -20,6 +20,27 @@ export class TextCell { injectFlexRenderContext>() } +@Component({ + selector: 'table-select-cell', + host: { + class: 'selection-cell', + }, + template: ` + + `, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class SelectCell { + readonly cell = injectTableCellContext() + readonly row = computed(() => this.cell().row) +} + @Component({ selector: 'span', host: { diff --git a/examples/angular/composable-tables/src/app/components/header-components.ts b/examples/angular/composable-tables/src/app/components/header-components.ts index 7afeaacb8e..65e195dd0b 100644 --- a/examples/angular/composable-tables/src/app/components/header-components.ts +++ b/examples/angular/composable-tables/src/app/components/header-components.ts @@ -9,7 +9,7 @@ // ) // } -import { Component, computed } from '@angular/core' +import { ChangeDetectionStrategy, Component, computed } from '@angular/core' import { flexRenderComponent } from '@tanstack/angular-table' import { FormsModule } from '@angular/forms' import { injectTableHeaderContext } from '../table' @@ -24,6 +24,26 @@ export function SortIndicator(): string | null { return `${sorted === 'asc' ? '🔼' : '🔽'}` } +@Component({ + selector: 'table-select-header', + host: { + class: 'selection-cell', + }, + template: ` + + `, + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class SelectHeader { + readonly header = injectTableHeaderContext() + readonly table = computed(() => this.header().getContext().table) +} + export function ColumnFilter(): FlexRenderComponent | null { const header = injectTableHeaderContext() if (!header().column.getCanFilter()) return null diff --git a/examples/angular/composable-tables/src/app/components/products-table/products-table.html b/examples/angular/composable-tables/src/app/components/products-table/products-table.html index ad0643dbea..f4eb639602 100644 --- a/examples/angular/composable-tables/src/app/components/products-table/products-table.html +++ b/examples/angular/composable-tables/src/app/components/products-table/products-table.html @@ -6,65 +6,67 @@ " /> - - - @for (headerGroup of table.getHeaderGroups(); track headerGroup.id) { - - @for (_header of headerGroup.headers; track _header.id) { - @let header = table.appHeader(_header); - @if (!header.isPlaceholder) { - + @for (footerGroup of table.getFooterGroups(); track footerGroup.id) { + + @for (footer of footerGroup.headers; track footer.id) { + + } + + } + +
- - {{ header }} - +
+ + + @for (headerGroup of table.getHeaderGroups(); track headerGroup.id) { + + @for (_header of headerGroup.headers; track _header.id) { + @let header = table.appHeader(_header); + @if (!header.isPlaceholder) { + + } + } + + } + + + @for (row of table.getRowModel().rows; track row.id) { + + @for (cell of row.getAllCells(); track cell.id) { + } - } - - } - - - @for (row of table.getRowModel().rows; track row.id) { - - @for (cell of row.getAllCells(); track cell.id) { - - } - - } - + + } + - - @for (footerGroup of table.getFooterGroups(); track footerGroup.id) { - - @for (footer of footerGroup.headers; track footer.id) { - - } - - } - -
+ + {{ header }} + - -
-
+ +
+
- -
+ +
+
+
+ + {{ cell }} - +
- - {{ cell }} - -
- @if (!footer.isPlaceholder) { - - {{ footer }} - - } -
+
+ @if (!footer.isPlaceholder) { + + {{ footer }} + + } +
+ diff --git a/examples/angular/composable-tables/src/app/components/products-table/products-table.ts b/examples/angular/composable-tables/src/app/components/products-table/products-table.ts index c8bad25b6d..303580cdd0 100644 --- a/examples/angular/composable-tables/src/app/components/products-table/products-table.ts +++ b/examples/angular/composable-tables/src/app/components/products-table/products-table.ts @@ -5,6 +5,7 @@ import { TanStackTable, TanStackTableCell, TanStackTableHeader, + flexRenderComponent, } from '@tanstack/angular-table' import { injectTanStackTableDevtools } from '@tanstack/angular-table-devtools' import { makeProductData } from '../../makeData' @@ -34,6 +35,11 @@ export class ProductsTable { readonly data = signal(makeProductData(1_000)) readonly columns = productColumnHelper.columns([ + productColumnHelper.display({ + id: 'select', + header: ({ header }) => flexRenderComponent(header.SelectHeader), + cell: ({ cell }) => flexRenderComponent(cell.SelectCell), + }), productColumnHelper.accessor('name', { header: 'Product Name', footer: (props) => props.column.id, @@ -66,6 +72,7 @@ export class ProductsTable { columns: this.columns, data: this.data(), getRowId: (row) => row.id, + enableRowSelection: true, // more table options })) diff --git a/examples/angular/composable-tables/src/app/components/users-table/users-table.html b/examples/angular/composable-tables/src/app/components/users-table/users-table.html index 3744b5b0f7..f08f9499c2 100644 --- a/examples/angular/composable-tables/src/app/components/users-table/users-table.html +++ b/examples/angular/composable-tables/src/app/components/users-table/users-table.html @@ -6,65 +6,67 @@ " /> - - - @for (headerGroup of table.getHeaderGroups(); track headerGroup.id) { - - @for (_header of headerGroup.headers; track _header.id) { - @let header = table.appHeader(_header); - @if (!header.isPlaceholder) { - + @for (footerGroup of table.getFooterGroups(); track footerGroup.id) { + + @for (footer of footerGroup.headers; track footer.id) { + + } + + } + +
- - {{ header }} - +
+ + + @for (headerGroup of table.getHeaderGroups(); track headerGroup.id) { + + @for (_header of headerGroup.headers; track _header.id) { + @let header = table.appHeader(_header); + @if (!header.isPlaceholder) { + + } + } + + } + + + @for (row of table.getRowModel().rows; track row.id) { + + @for (cell of row.getAllCells(); track cell.id) { + } - } - - } - - - @for (row of table.getRowModel().rows; track row.id) { - - @for (cell of row.getAllCells(); track cell.id) { - - } - - } - + + } + - - @for (footerGroup of table.getFooterGroups(); track footerGroup.id) { - - @for (footer of footerGroup.headers; track footer.id) { - - } - - } - -
+ + {{ header }} + - -
-
+ +
+
- -
+ +
+
+
+ + {{ cell }} - +
- - {{ cell }} - -
- @if (!footer.isPlaceholder) { - - {{ footer }} - - } -
+
+ @if (!footer.isPlaceholder) { + + {{ footer }} + + } +
+ diff --git a/examples/angular/composable-tables/src/app/components/users-table/users-table.ts b/examples/angular/composable-tables/src/app/components/users-table/users-table.ts index 7441694757..ac07756c0d 100644 --- a/examples/angular/composable-tables/src/app/components/users-table/users-table.ts +++ b/examples/angular/composable-tables/src/app/components/users-table/users-table.ts @@ -35,6 +35,11 @@ export class UsersTable { readonly data = signal(makeData(1_000)) readonly columns = personColumnHelper.columns([ + personColumnHelper.display({ + id: 'select', + header: ({ header }) => flexRenderComponent(header.SelectHeader), + cell: ({ cell }) => flexRenderComponent(cell.SelectCell), + }), personColumnHelper.accessor('firstName', { header: 'First Name', footer: ({ header }) => flexRenderComponent(header.FooterColumnId), @@ -77,6 +82,7 @@ export class UsersTable { columns: this.columns, data: this.data(), debugTable: true, + enableRowSelection: true, // more table options })) diff --git a/examples/angular/composable-tables/src/app/table.ts b/examples/angular/composable-tables/src/app/table.ts index cff38db8bc..5d6a897920 100644 --- a/examples/angular/composable-tables/src/app/table.ts +++ b/examples/angular/composable-tables/src/app/table.ts @@ -13,6 +13,7 @@ import { createTableHook, filterFns, rowPaginationFeature, + rowSelectionFeature, rowSortingFeature, sortFns, tableFeatures, @@ -31,6 +32,7 @@ import { PriceCell, ProgressCell, RowActionsCell, + SelectCell, StatusCell, TextCell, } from './components/cell-components' @@ -39,6 +41,7 @@ import { ColumnFilter, FooterColumnId, FooterSum, + SelectHeader, SortIndicator, } from './components/header-components' @@ -66,6 +69,7 @@ export const { features: tableFeatures({ columnFilteringFeature, rowPaginationFeature, + rowSelectionFeature, rowSortingFeature, sortedRowModel: createSortedRowModel(), filteredRowModel: createFilteredRowModel(), @@ -86,6 +90,7 @@ export const { // Register cell-level components (accessible via cell.ComponentName in AppCell) cellComponents: { + SelectCell, TextCell, NumberCell, ProgressCell, @@ -97,6 +102,7 @@ export const { // Register header/footer-level components (accessible via header.ComponentName in AppHeader/AppFooter) headerComponents: { + SelectHeader, SortIndicator, ColumnFilter, FooterColumnId, diff --git a/examples/angular/composable-tables/src/styles.css b/examples/angular/composable-tables/src/styles.css index 4d8fef0142..b171dde3f0 100644 --- a/examples/angular/composable-tables/src/styles.css +++ b/examples/angular/composable-tables/src/styles.css @@ -35,6 +35,18 @@ tfoot th { font-weight: normal; } +.table-scroll { + max-height: 400px; + overflow: auto; + border: 1px solid lightgray; +} + +.table-scroll thead th { + position: sticky; + top: 0; + z-index: 1; +} + .table-container { padding: 16px; max-width: 1200px; diff --git a/examples/angular/custom-plugin/package.json b/examples/angular/custom-plugin/package.json index 11bfb737da..50c62db2e3 100644 --- a/examples/angular/custom-plugin/package.json +++ b/examples/angular/custom-plugin/package.json @@ -17,7 +17,7 @@ "@angular/forms": "^22.0.0", "@angular/platform-browser": "^22.0.0", "@angular/router": "^22.0.0", - "@tanstack/angular-table": "^9.0.0-beta.12", + "@tanstack/angular-table": "^9.0.0-beta.15", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, diff --git a/examples/angular/editable/package.json b/examples/angular/editable/package.json index ca43cad2a8..c92f42bd7f 100644 --- a/examples/angular/editable/package.json +++ b/examples/angular/editable/package.json @@ -18,7 +18,7 @@ "@angular/platform-browser": "^22.0.0", "@angular/router": "^22.0.0", "@faker-js/faker": "^10.4.0", - "@tanstack/angular-table": "^9.0.0-beta.12", + "@tanstack/angular-table": "^9.0.0-beta.15", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, diff --git a/examples/angular/expanding/package.json b/examples/angular/expanding/package.json index 571afe8f69..2c59c7fe4e 100644 --- a/examples/angular/expanding/package.json +++ b/examples/angular/expanding/package.json @@ -18,7 +18,7 @@ "@angular/platform-browser": "^22.0.0", "@angular/router": "^22.0.0", "@faker-js/faker": "^10.4.0", - "@tanstack/angular-table": "^9.0.0-beta.12", + "@tanstack/angular-table": "^9.0.0-beta.15", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, diff --git a/examples/angular/filters-faceted/package.json b/examples/angular/filters-faceted/package.json index 5b692e55a3..ac39e9aed0 100644 --- a/examples/angular/filters-faceted/package.json +++ b/examples/angular/filters-faceted/package.json @@ -19,7 +19,7 @@ "@angular/router": "^22.0.0", "@faker-js/faker": "^10.4.0", "@tanstack/angular-pacer": "^0.23.1", - "@tanstack/angular-table": "^9.0.0-beta.12", + "@tanstack/angular-table": "^9.0.0-beta.15", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, diff --git a/examples/angular/filters-fuzzy/package.json b/examples/angular/filters-fuzzy/package.json index 8239af5fe2..9e37afad25 100644 --- a/examples/angular/filters-fuzzy/package.json +++ b/examples/angular/filters-fuzzy/package.json @@ -19,7 +19,7 @@ "@angular/router": "^22.0.0", "@faker-js/faker": "^10.4.0", "@tanstack/angular-pacer": "^0.23.1", - "@tanstack/angular-table": "^9.0.0-beta.12", + "@tanstack/angular-table": "^9.0.0-beta.15", "@tanstack/match-sorter-utils": "^9.0.0-beta.0", "rxjs": "~7.8.2", "tslib": "^2.8.1" diff --git a/examples/angular/filters/package.json b/examples/angular/filters/package.json index d9ad4426c7..eb665627a7 100644 --- a/examples/angular/filters/package.json +++ b/examples/angular/filters/package.json @@ -19,7 +19,7 @@ "@angular/router": "^22.0.0", "@faker-js/faker": "^10.4.0", "@tanstack/angular-pacer": "^0.23.1", - "@tanstack/angular-table": "^9.0.0-beta.12", + "@tanstack/angular-table": "^9.0.0-beta.15", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, diff --git a/examples/angular/grouping/package.json b/examples/angular/grouping/package.json index a61759cd07..66bb72a6f4 100644 --- a/examples/angular/grouping/package.json +++ b/examples/angular/grouping/package.json @@ -18,7 +18,7 @@ "@angular/platform-browser": "^22.0.0", "@angular/router": "^22.0.0", "@faker-js/faker": "^10.4.0", - "@tanstack/angular-table": "^9.0.0-beta.12", + "@tanstack/angular-table": "^9.0.0-beta.15", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, diff --git a/examples/angular/kitchen-sink/package.json b/examples/angular/kitchen-sink/package.json index 8293917b24..0692cfaf5c 100644 --- a/examples/angular/kitchen-sink/package.json +++ b/examples/angular/kitchen-sink/package.json @@ -19,8 +19,8 @@ "@angular/router": "^22.0.0", "@faker-js/faker": "^10.4.0", "@tanstack/angular-devtools": "^0.0.4", - "@tanstack/angular-table": "^9.0.0-beta.12", - "@tanstack/angular-table-devtools": "^9.0.0-beta.12", + "@tanstack/angular-table": "^9.0.0-beta.15", + "@tanstack/angular-table-devtools": "^9.0.0-beta.15", "@tanstack/match-sorter-utils": "^9.0.0-beta.0", "rxjs": "~7.8.2", "tslib": "^2.8.1" diff --git a/examples/angular/pagination/package.json b/examples/angular/pagination/package.json index 46872e1e4d..f0f771d0a8 100644 --- a/examples/angular/pagination/package.json +++ b/examples/angular/pagination/package.json @@ -18,7 +18,7 @@ "@angular/platform-browser": "^22.0.0", "@angular/router": "^22.0.0", "@faker-js/faker": "^10.4.0", - "@tanstack/angular-table": "^9.0.0-beta.12", + "@tanstack/angular-table": "^9.0.0-beta.15", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, diff --git a/examples/angular/remote-data/package.json b/examples/angular/remote-data/package.json index e625f99775..5bd2d57f3e 100644 --- a/examples/angular/remote-data/package.json +++ b/examples/angular/remote-data/package.json @@ -23,7 +23,7 @@ "@angular/platform-server": "^22.0.0", "@angular/router": "^22.0.0", "@angular/ssr": "^22.0.0", - "@tanstack/angular-table": "^9.0.0-beta.12", + "@tanstack/angular-table": "^9.0.0-beta.15", "express": "^5.2.1", "rxjs": "~7.8.2" }, diff --git a/examples/angular/row-dnd/package.json b/examples/angular/row-dnd/package.json index 75549a6ed4..82f6e01cc5 100644 --- a/examples/angular/row-dnd/package.json +++ b/examples/angular/row-dnd/package.json @@ -19,7 +19,7 @@ "@angular/platform-browser": "^22.0.0", "@angular/router": "^22.0.0", "@faker-js/faker": "^10.4.0", - "@tanstack/angular-table": "^9.0.0-beta.12", + "@tanstack/angular-table": "^9.0.0-beta.15", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, diff --git a/examples/angular/row-pinning/package.json b/examples/angular/row-pinning/package.json index 1b06dbba9d..6ba4442da8 100644 --- a/examples/angular/row-pinning/package.json +++ b/examples/angular/row-pinning/package.json @@ -18,7 +18,7 @@ "@angular/platform-browser": "^22.0.0", "@angular/router": "^22.0.0", "@faker-js/faker": "^10.4.0", - "@tanstack/angular-table": "^9.0.0-beta.12", + "@tanstack/angular-table": "^9.0.0-beta.15", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, diff --git a/examples/angular/row-selection-signal/package.json b/examples/angular/row-selection-signal/package.json index 4343aa2cd7..10f3b94488 100644 --- a/examples/angular/row-selection-signal/package.json +++ b/examples/angular/row-selection-signal/package.json @@ -21,8 +21,8 @@ "@angular/platform-browser-dynamic": "^22.0.0", "@faker-js/faker": "^10.4.0", "@tanstack/angular-devtools": "^0.0.4", - "@tanstack/angular-table": "^9.0.0-beta.12", - "@tanstack/angular-table-devtools": "^9.0.0-beta.12", + "@tanstack/angular-table": "^9.0.0-beta.15", + "@tanstack/angular-table-devtools": "^9.0.0-beta.15", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, diff --git a/examples/angular/row-selection/package.json b/examples/angular/row-selection/package.json index 6a4b5988c1..2e80a8df45 100644 --- a/examples/angular/row-selection/package.json +++ b/examples/angular/row-selection/package.json @@ -20,8 +20,8 @@ "@angular/router": "^22.0.0", "@faker-js/faker": "^10.4.0", "@tanstack/angular-devtools": "^0.0.4", - "@tanstack/angular-table": "^9.0.0-beta.12", - "@tanstack/angular-table-devtools": "^9.0.0-beta.12", + "@tanstack/angular-table": "^9.0.0-beta.15", + "@tanstack/angular-table-devtools": "^9.0.0-beta.15", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, diff --git a/examples/angular/signal-input/package.json b/examples/angular/signal-input/package.json index 7f592716ad..7df4aa63a3 100644 --- a/examples/angular/signal-input/package.json +++ b/examples/angular/signal-input/package.json @@ -19,7 +19,7 @@ "@angular/platform-browser": "^22.0.0", "@angular/router": "^22.0.0", "@faker-js/faker": "^10.4.0", - "@tanstack/angular-table": "^9.0.0-beta.12", + "@tanstack/angular-table": "^9.0.0-beta.15", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, diff --git a/examples/angular/sorting/package.json b/examples/angular/sorting/package.json index 6d8f98e986..ff6a327826 100644 --- a/examples/angular/sorting/package.json +++ b/examples/angular/sorting/package.json @@ -18,7 +18,7 @@ "@angular/platform-browser": "^22.0.0", "@angular/router": "^22.0.0", "@faker-js/faker": "^10.4.0", - "@tanstack/angular-table": "^9.0.0-beta.12", + "@tanstack/angular-table": "^9.0.0-beta.15", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, diff --git a/examples/angular/sub-components/package.json b/examples/angular/sub-components/package.json index 0c0c09b3aa..a7a592d357 100644 --- a/examples/angular/sub-components/package.json +++ b/examples/angular/sub-components/package.json @@ -18,7 +18,7 @@ "@angular/platform-browser": "^22.0.0", "@angular/router": "^22.0.0", "@faker-js/faker": "^10.4.0", - "@tanstack/angular-table": "^9.0.0-beta.12", + "@tanstack/angular-table": "^9.0.0-beta.15", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, diff --git a/examples/angular/virtualized-columns/package.json b/examples/angular/virtualized-columns/package.json index fd8bae849c..d8973072f3 100644 --- a/examples/angular/virtualized-columns/package.json +++ b/examples/angular/virtualized-columns/package.json @@ -18,7 +18,7 @@ "@angular/platform-browser": "^22.0.0", "@angular/router": "^22.0.0", "@faker-js/faker": "^10.4.0", - "@tanstack/angular-table": "^9.0.0-beta.12", + "@tanstack/angular-table": "^9.0.0-beta.15", "@tanstack/angular-virtual": "^5.0.4", "rxjs": "~7.8.2", "tslib": "^2.8.1" diff --git a/examples/angular/virtualized-infinite-scrolling/package.json b/examples/angular/virtualized-infinite-scrolling/package.json index 1cf5ac68b8..9526e52be2 100644 --- a/examples/angular/virtualized-infinite-scrolling/package.json +++ b/examples/angular/virtualized-infinite-scrolling/package.json @@ -18,7 +18,7 @@ "@angular/platform-browser": "^22.0.0", "@angular/router": "^22.0.0", "@faker-js/faker": "^10.4.0", - "@tanstack/angular-table": "^9.0.0-beta.12", + "@tanstack/angular-table": "^9.0.0-beta.15", "@tanstack/angular-virtual": "^5.0.4", "rxjs": "~7.8.2", "tslib": "^2.8.1" diff --git a/examples/angular/virtualized-rows/package.json b/examples/angular/virtualized-rows/package.json index 90ac5773b3..a0436021e9 100644 --- a/examples/angular/virtualized-rows/package.json +++ b/examples/angular/virtualized-rows/package.json @@ -18,7 +18,7 @@ "@angular/platform-browser": "^22.0.0", "@angular/router": "^22.0.0", "@faker-js/faker": "^10.4.0", - "@tanstack/angular-table": "^9.0.0-beta.12", + "@tanstack/angular-table": "^9.0.0-beta.15", "@tanstack/angular-virtual": "^5.0.4", "rxjs": "~7.8.2", "tslib": "^2.8.1" diff --git a/examples/angular/with-tanstack-form/package.json b/examples/angular/with-tanstack-form/package.json index f4bdd32db7..3add822845 100644 --- a/examples/angular/with-tanstack-form/package.json +++ b/examples/angular/with-tanstack-form/package.json @@ -19,7 +19,7 @@ "@angular/router": "^22.0.0", "@faker-js/faker": "^10.4.0", "@tanstack/angular-form": "^1.33.0", - "@tanstack/angular-table": "^9.0.0-beta.12", + "@tanstack/angular-table": "^9.0.0-beta.15", "rxjs": "~7.8.2", "tslib": "^2.8.1", "zod": "^4.4.3" diff --git a/examples/angular/with-tanstack-query/package.json b/examples/angular/with-tanstack-query/package.json index c94ccfa93f..61b5c9ea15 100644 --- a/examples/angular/with-tanstack-query/package.json +++ b/examples/angular/with-tanstack-query/package.json @@ -19,7 +19,7 @@ "@angular/router": "^22.0.0", "@faker-js/faker": "^10.4.0", "@tanstack/angular-query-experimental": "^5.101.0", - "@tanstack/angular-table": "^9.0.0-beta.12", + "@tanstack/angular-table": "^9.0.0-beta.15", "rxjs": "~7.8.2", "tslib": "^2.8.1" }, diff --git a/examples/lit/basic-app-table/package.json b/examples/lit/basic-app-table/package.json index 8640d1e980..3b883b6b18 100644 --- a/examples/lit/basic-app-table/package.json +++ b/examples/lit/basic-app-table/package.json @@ -11,7 +11,7 @@ "dependencies": { "@faker-js/faker": "^10.4.0", "@lit/context": "^1.1.6", - "@tanstack/lit-table": "^9.0.0-beta.12", + "@tanstack/lit-table": "^9.0.0-beta.15", "lit": "^3.3.3" }, "devDependencies": { diff --git a/examples/lit/basic-external-atoms/package.json b/examples/lit/basic-external-atoms/package.json index 3662db2622..f9d32aeac4 100644 --- a/examples/lit/basic-external-atoms/package.json +++ b/examples/lit/basic-external-atoms/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/lit-table": "^9.0.0-beta.12", + "@tanstack/lit-table": "^9.0.0-beta.15", "@tanstack/store": "^0.11.0", "lit": "^3.3.3" }, diff --git a/examples/lit/basic-external-state/package.json b/examples/lit/basic-external-state/package.json index acf5ee9ab0..090ad237d1 100644 --- a/examples/lit/basic-external-state/package.json +++ b/examples/lit/basic-external-state/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/lit-table": "^9.0.0-beta.12", + "@tanstack/lit-table": "^9.0.0-beta.15", "lit": "^3.3.3" }, "devDependencies": { diff --git a/examples/lit/basic-table-controller/package.json b/examples/lit/basic-table-controller/package.json index f7f9640eed..964700cd87 100644 --- a/examples/lit/basic-table-controller/package.json +++ b/examples/lit/basic-table-controller/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/lit-table": "^9.0.0-beta.12", + "@tanstack/lit-table": "^9.0.0-beta.15", "lit": "^3.3.3" }, "devDependencies": { diff --git a/examples/lit/column-groups/package.json b/examples/lit/column-groups/package.json index 74a8ecbdd0..de4b506b6b 100644 --- a/examples/lit/column-groups/package.json +++ b/examples/lit/column-groups/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/lit-table": "^9.0.0-beta.12", + "@tanstack/lit-table": "^9.0.0-beta.15", "lit": "^3.3.3" }, "devDependencies": { diff --git a/examples/lit/column-ordering/package.json b/examples/lit/column-ordering/package.json index 2a696a57f9..52a6249aa2 100644 --- a/examples/lit/column-ordering/package.json +++ b/examples/lit/column-ordering/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/lit-table": "^9.0.0-beta.12", + "@tanstack/lit-table": "^9.0.0-beta.15", "lit": "^3.3.3" }, "devDependencies": { diff --git a/examples/lit/column-pinning-split/package.json b/examples/lit/column-pinning-split/package.json index ca25b47620..73fdf553b4 100644 --- a/examples/lit/column-pinning-split/package.json +++ b/examples/lit/column-pinning-split/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/lit-table": "^9.0.0-beta.12", + "@tanstack/lit-table": "^9.0.0-beta.15", "lit": "^3.3.3" }, "devDependencies": { diff --git a/examples/lit/column-pinning-sticky/package.json b/examples/lit/column-pinning-sticky/package.json index 01604e86da..a80dad168d 100644 --- a/examples/lit/column-pinning-sticky/package.json +++ b/examples/lit/column-pinning-sticky/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/lit-table": "^9.0.0-beta.12", + "@tanstack/lit-table": "^9.0.0-beta.15", "lit": "^3.3.3" }, "devDependencies": { diff --git a/examples/lit/column-pinning/package.json b/examples/lit/column-pinning/package.json index 9eb6e93443..e2a221d464 100644 --- a/examples/lit/column-pinning/package.json +++ b/examples/lit/column-pinning/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/lit-table": "^9.0.0-beta.12", + "@tanstack/lit-table": "^9.0.0-beta.15", "lit": "^3.3.3" }, "devDependencies": { diff --git a/examples/lit/column-resizing-performant/package.json b/examples/lit/column-resizing-performant/package.json index fa83514031..55ea1aa1df 100644 --- a/examples/lit/column-resizing-performant/package.json +++ b/examples/lit/column-resizing-performant/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/lit-table": "^9.0.0-beta.12", + "@tanstack/lit-table": "^9.0.0-beta.15", "lit": "^3.3.3" }, "devDependencies": { diff --git a/examples/lit/column-resizing/package.json b/examples/lit/column-resizing/package.json index 71f56d062a..1cd59d412c 100644 --- a/examples/lit/column-resizing/package.json +++ b/examples/lit/column-resizing/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/lit-table": "^9.0.0-beta.12", + "@tanstack/lit-table": "^9.0.0-beta.15", "lit": "^3.3.3" }, "devDependencies": { diff --git a/examples/lit/column-sizing/package.json b/examples/lit/column-sizing/package.json index 3c25ae76ea..3e88618b51 100644 --- a/examples/lit/column-sizing/package.json +++ b/examples/lit/column-sizing/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/lit-table": "^9.0.0-beta.12", + "@tanstack/lit-table": "^9.0.0-beta.15", "lit": "^3.3.3" }, "devDependencies": { diff --git a/examples/lit/column-visibility/package.json b/examples/lit/column-visibility/package.json index 9def67d9ed..c970309361 100644 --- a/examples/lit/column-visibility/package.json +++ b/examples/lit/column-visibility/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/lit-table": "^9.0.0-beta.12", + "@tanstack/lit-table": "^9.0.0-beta.15", "lit": "^3.3.3" }, "devDependencies": { diff --git a/examples/lit/composable-tables/package.json b/examples/lit/composable-tables/package.json index 399db4460d..9c3412b02e 100644 --- a/examples/lit/composable-tables/package.json +++ b/examples/lit/composable-tables/package.json @@ -11,7 +11,7 @@ "dependencies": { "@faker-js/faker": "^10.4.0", "@lit/context": "^1.1.6", - "@tanstack/lit-table": "^9.0.0-beta.12", + "@tanstack/lit-table": "^9.0.0-beta.15", "lit": "^3.3.3" }, "devDependencies": { diff --git a/examples/lit/composable-tables/src/components/products-table.ts b/examples/lit/composable-tables/src/components/products-table.ts index 96d75df3c4..1c40109b92 100644 --- a/examples/lit/composable-tables/src/components/products-table.ts +++ b/examples/lit/composable-tables/src/components/products-table.ts @@ -11,6 +11,26 @@ const productColumnHelper = createAppColumnHelper() // Define columns — different structure than Users table, same reusable components const columns = productColumnHelper.columns([ + productColumnHelper.display({ + id: 'select', + header: ({ table }) => html` + + `, + cell: ({ row }) => html` + + `, + }), productColumnHelper.accessor('name', { header: 'Product Name', footer: (props) => props.column.id, @@ -55,11 +75,13 @@ export class ProductsTable extends LitElement { get data() { return host.data }, + enableRowSelection: true, }, (state) => ({ pagination: state.pagination, sorting: state.sorting, columnFilters: state.columnFilters, + rowSelection: state.rowSelection, }), ) })() @@ -88,104 +110,109 @@ export class ProductsTable extends LitElement { > - - - ${table.getHeaderGroups().map( - (headerGroup) => html` - - ${headerGroup.headers.map((h) => - table.AppHeader( - h, - (header) => html` - - `, - ), - )} - - `, - )} - - - ${table.getRowModel().rows.map( - (row) => html` - - ${row - .getAllCells() - .map((c) => - table.AppCell( - c, - (cell) => html` `, - ), - )} - - `, - )} - - - ${table.getFooterGroups().map( - (footerGroup) => html` - - ${footerGroup.headers.map((f) => - table.AppFooter(f, (footer) => { - const columnId = footer.column.id - const hasFilter = columnFilters.some( - (cf) => cf.id === columnId, - ) - return html` - + `, + )} + + + ${table.getRowModel().rows.map( + (row) => html` + + ${row + .getAllCells() + .map((c) => + table.AppCell( + c, + (cell) => html` `, + ), + )} + + `, + )} + + + ${table.getFooterGroups().map( + (footerGroup) => html` + + ${footerGroup.headers.map((f) => + table.AppFooter(f, (footer) => { + const columnId = footer.column.id + const hasFilter = columnFilters.some( + (cf) => cf.id === columnId, + ) + return html` + + ` + }), + )} + + `, + )} + +
- ${header.isPlaceholder - ? nothing - : html` - ${header.FlexRender()} ${header.SortIndicator()} - ${header.ColumnFilter()} - ${sorting.length > 1 && - sorting.findIndex( - (s) => s.id === header.column.id, - ) > -1 - ? html`${sorting.findIndex( - (s) => s.id === header.column.id, - ) + 1}` - : nothing} - `} -
${cell.FlexRender()}
- ${footer.isPlaceholder - ? nothing - : columnId === 'price' || - columnId === 'stock' || - columnId === 'rating' - ? html` - ${footer.FooterSum()} - ${hasFilter - ? html` - (filtered)` - : nothing} - ` +
+ + + ${table.getHeaderGroups().map( + (headerGroup) => html` + + ${headerGroup.headers.map((h) => + table.AppHeader( + h, + (header) => html` + - `, - )} - -
+ ${header.isPlaceholder + ? nothing : html` - ${footer.FooterColumnId()} - ${hasFilter - ? html` - ✓ 1 && + sorting.findIndex( + (s) => s.id === header.column.id, + ) > -1 + ? html`${sorting.findIndex( + (s) => s.id === header.column.id, + ) + 1}` : nothing} `} - - ` - }), - )} -
+ + `, + ), + )} +
${cell.FlexRender()}
+ ${footer.isPlaceholder + ? nothing + : columnId === 'price' || + columnId === 'stock' || + columnId === 'rating' + ? html` + ${footer.FooterSum()} + ${hasFilter + ? html` + (filtered)` + : nothing} + ` + : columnId === 'select' + ? nothing + : html` + ${footer.FooterColumnId()} + ${hasFilter + ? html` + ✓` + : nothing} + `} +
+ diff --git a/examples/lit/composable-tables/src/components/users-table.ts b/examples/lit/composable-tables/src/components/users-table.ts index 737ba0f5a2..7c43bf5112 100644 --- a/examples/lit/composable-tables/src/components/users-table.ts +++ b/examples/lit/composable-tables/src/components/users-table.ts @@ -13,6 +13,26 @@ const personColumnHelper = createAppColumnHelper() // NOTE: Use createAppColumnHelper (not createColumnHelper) to get pre-bound // component types on cell/header objects (e.g., cell.TextCell, header.SortIndicator). const columns = personColumnHelper.columns([ + personColumnHelper.display({ + id: 'select', + header: ({ table }) => html` + + `, + cell: ({ row }) => html` + + `, + }), personColumnHelper.accessor('firstName', { header: 'First Name', footer: (props) => props.column.id, @@ -68,12 +88,14 @@ export class UsersTable extends LitElement { get data() { return host.data }, + enableRowSelection: true, debugTable: true, }, (state) => ({ pagination: state.pagination, sorting: state.sorting, columnFilters: state.columnFilters, + rowSelection: state.rowSelection, }), ) })() @@ -102,106 +124,110 @@ export class UsersTable extends LitElement { > - - - ${table.getHeaderGroups().map( - (headerGroup) => html` - - ${headerGroup.headers.map((h) => - table.AppHeader( - h, - (header) => html` - - `, - ), - )} - - `, - )} - - - ${table.getRowModel().rows.map( - (row) => html` - - ${row - .getAllCells() - .map((c) => - table.AppCell( - c, - (cell) => html` `, - ), - )} - - `, - )} - - - ${table.getFooterGroups().map( - (footerGroup) => html` - - ${footerGroup.headers.map((f) => - table.AppFooter(f, (footer) => { - const columnId = footer.column.id - const hasFilter = columnFilters.some( - (cf) => cf.id === columnId, - ) - return html` - + ` + }), + )} + + `, + )} + +
- ${header.isPlaceholder - ? nothing - : html` - ${header.FlexRender()} ${header.SortIndicator()} - ${header.ColumnFilter()} - ${sorting.length > 1 && - sorting.findIndex( - (s) => s.id === header.column.id, - ) > -1 - ? html`${sorting.findIndex( - (s) => s.id === header.column.id, - ) + 1}` - : nothing} - `} -
${cell.FlexRender()}
- ${footer.isPlaceholder - ? nothing - : columnId === 'age' || - columnId === 'visits' || - columnId === 'progress' - ? html` - ${footer.FooterSum()} - ${hasFilter - ? html` - (filtered) + + + ${table.getHeaderGroups().map( + (headerGroup) => html` + + ${headerGroup.headers.map((h) => + table.AppHeader( + h, + (header) => html` + + `, + ), + )} + + `, + )} + + + ${table.getRowModel().rows.map( + (row) => html` + + ${row + .getAllCells() + .map((c) => + table.AppCell( + c, + (cell) => html` `, + ), + )} + + `, + )} + + + ${table.getFooterGroups().map( + (footerGroup) => html` + + ${footerGroup.headers.map((f) => + table.AppFooter(f, (footer) => { + const columnId = footer.column.id + const hasFilter = columnFilters.some( + (cf) => cf.id === columnId, + ) + return html` + - ` - }), - )} - - `, - )} - -
+ ${header.isPlaceholder + ? nothing + : html` + ${header.FlexRender()} + ${header.SortIndicator()} + ${header.ColumnFilter()} + ${sorting.length > 1 && + sorting.findIndex( + (s) => s.id === header.column.id, + ) > -1 + ? html`${sorting.findIndex( + (s) => s.id === header.column.id, + ) + 1}` : nothing} - ` - : columnId === 'actions' - ? nothing - : html` - ${footer.FooterColumnId()} + `} +
${cell.FlexRender()}
+ ${footer.isPlaceholder + ? nothing + : columnId === 'age' || + columnId === 'visits' || + columnId === 'progress' + ? html` + ${footer.FooterSum()} ${hasFilter ? html` - ✓` : nothing} - `} -
+ ` + : columnId === 'actions' || + columnId === 'select' + ? nothing + : html` + ${footer.FooterColumnId()} + ${hasFilter + ? html` + ✓` + : nothing} + `} +
+ diff --git a/examples/lit/composable-tables/src/hooks/table.ts b/examples/lit/composable-tables/src/hooks/table.ts index 68327899b6..58c0e5f4f6 100644 --- a/examples/lit/composable-tables/src/hooks/table.ts +++ b/examples/lit/composable-tables/src/hooks/table.ts @@ -6,6 +6,7 @@ import { createTableHook, filterFns, rowPaginationFeature, + rowSelectionFeature, rowSortingFeature, sortFns, tableFeatures, @@ -33,6 +34,7 @@ import { export const features = tableFeatures({ columnFilteringFeature, rowPaginationFeature, + rowSelectionFeature, rowSortingFeature, sortedRowModel: createSortedRowModel(), filteredRowModel: createFilteredRowModel(), diff --git a/examples/lit/composable-tables/src/index.css b/examples/lit/composable-tables/src/index.css index 4d8fef0142..d03f22d5b7 100644 --- a/examples/lit/composable-tables/src/index.css +++ b/examples/lit/composable-tables/src/index.css @@ -43,6 +43,20 @@ tfoot th { border-spacing: 0; } +/* Fixed-height, scrollable region around the table. With a page size larger + than ~12 rows the body overflows and scrolls. */ +.table-scroll { + max-height: 400px; + overflow: auto; + border: 1px solid lightgray; +} + +.table-scroll thead th { + position: sticky; + top: 0; + z-index: 1; +} + .pagination { display: flex; align-items: center; diff --git a/examples/lit/expanding/package.json b/examples/lit/expanding/package.json index fbf52b400f..cc181da289 100644 --- a/examples/lit/expanding/package.json +++ b/examples/lit/expanding/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/lit-table": "^9.0.0-beta.12", + "@tanstack/lit-table": "^9.0.0-beta.15", "lit": "^3.3.3" }, "devDependencies": { diff --git a/examples/lit/filters-faceted/package.json b/examples/lit/filters-faceted/package.json index f38a44d1b5..13a9f4adbe 100644 --- a/examples/lit/filters-faceted/package.json +++ b/examples/lit/filters-faceted/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/lit-table": "^9.0.0-beta.12", + "@tanstack/lit-table": "^9.0.0-beta.15", "lit": "^3.3.3" }, "devDependencies": { diff --git a/examples/lit/filters-fuzzy/package.json b/examples/lit/filters-fuzzy/package.json index 53168e9004..0d33504cfc 100644 --- a/examples/lit/filters-fuzzy/package.json +++ b/examples/lit/filters-fuzzy/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/lit-table": "^9.0.0-beta.12", + "@tanstack/lit-table": "^9.0.0-beta.15", "@tanstack/match-sorter-utils": "^9.0.0-beta.0", "lit": "^3.3.3" }, diff --git a/examples/lit/filters/package.json b/examples/lit/filters/package.json index ba9930bf8e..680db7d6b4 100644 --- a/examples/lit/filters/package.json +++ b/examples/lit/filters/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/lit-table": "^9.0.0-beta.12", + "@tanstack/lit-table": "^9.0.0-beta.15", "lit": "^3.3.3" }, "devDependencies": { diff --git a/examples/lit/grouping/package.json b/examples/lit/grouping/package.json index 866441ab8e..3db541867b 100644 --- a/examples/lit/grouping/package.json +++ b/examples/lit/grouping/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/lit-table": "^9.0.0-beta.12", + "@tanstack/lit-table": "^9.0.0-beta.15", "lit": "^3.3.3" }, "devDependencies": { diff --git a/examples/lit/kitchen-sink/package.json b/examples/lit/kitchen-sink/package.json index 0b56da934c..f81be96e0e 100644 --- a/examples/lit/kitchen-sink/package.json +++ b/examples/lit/kitchen-sink/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/lit-table": "^9.0.0-beta.12", + "@tanstack/lit-table": "^9.0.0-beta.15", "@tanstack/match-sorter-utils": "^9.0.0-beta.0", "lit": "^3.3.3" }, diff --git a/examples/lit/pagination/package.json b/examples/lit/pagination/package.json index 6ac5cd9975..fa44975caa 100644 --- a/examples/lit/pagination/package.json +++ b/examples/lit/pagination/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/lit-table": "^9.0.0-beta.12", + "@tanstack/lit-table": "^9.0.0-beta.15", "lit": "^3.3.3" }, "devDependencies": { diff --git a/examples/lit/row-pinning/package.json b/examples/lit/row-pinning/package.json index 8f301fa011..cdbabd4ca8 100644 --- a/examples/lit/row-pinning/package.json +++ b/examples/lit/row-pinning/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/lit-table": "^9.0.0-beta.12", + "@tanstack/lit-table": "^9.0.0-beta.15", "lit": "^3.3.3" }, "devDependencies": { diff --git a/examples/lit/row-selection/package.json b/examples/lit/row-selection/package.json index efd0372332..b6d0dd5082 100644 --- a/examples/lit/row-selection/package.json +++ b/examples/lit/row-selection/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/lit-table": "^9.0.0-beta.12", + "@tanstack/lit-table": "^9.0.0-beta.15", "lit": "^3.3.3" }, "devDependencies": { diff --git a/examples/lit/sorting-dynamic-data/package.json b/examples/lit/sorting-dynamic-data/package.json index 93f79266df..4ba91f2b09 100644 --- a/examples/lit/sorting-dynamic-data/package.json +++ b/examples/lit/sorting-dynamic-data/package.json @@ -9,7 +9,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/lit-table": "^9.0.0-beta.12", + "@tanstack/lit-table": "^9.0.0-beta.15", "lit": "^3.3.3" }, "devDependencies": { diff --git a/examples/lit/sorting/package.json b/examples/lit/sorting/package.json index b6fe411daa..e10b9c76c1 100644 --- a/examples/lit/sorting/package.json +++ b/examples/lit/sorting/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/lit-table": "^9.0.0-beta.12", + "@tanstack/lit-table": "^9.0.0-beta.15", "lit": "^3.3.3" }, "devDependencies": { diff --git a/examples/lit/sub-components/package.json b/examples/lit/sub-components/package.json index f584690234..a0310cf031 100644 --- a/examples/lit/sub-components/package.json +++ b/examples/lit/sub-components/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/lit-table": "^9.0.0-beta.12", + "@tanstack/lit-table": "^9.0.0-beta.15", "lit": "^3.3.3" }, "devDependencies": { diff --git a/examples/lit/virtualized-columns/package.json b/examples/lit/virtualized-columns/package.json index a28cd264f1..5ff44e41db 100644 --- a/examples/lit/virtualized-columns/package.json +++ b/examples/lit/virtualized-columns/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/lit-table": "^9.0.0-beta.12", + "@tanstack/lit-table": "^9.0.0-beta.15", "@tanstack/lit-virtual": "^3.13.29", "lit": "^3.3.3" }, diff --git a/examples/lit/virtualized-infinite-scrolling/package.json b/examples/lit/virtualized-infinite-scrolling/package.json index aad7615613..60370d366b 100644 --- a/examples/lit/virtualized-infinite-scrolling/package.json +++ b/examples/lit/virtualized-infinite-scrolling/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/lit-table": "^9.0.0-beta.12", + "@tanstack/lit-table": "^9.0.0-beta.15", "@tanstack/lit-virtual": "^3.13.29", "lit": "^3.3.3" }, diff --git a/examples/lit/virtualized-rows/package.json b/examples/lit/virtualized-rows/package.json index 7e2a6ddcd7..ccf63b6fe8 100644 --- a/examples/lit/virtualized-rows/package.json +++ b/examples/lit/virtualized-rows/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/lit-table": "^9.0.0-beta.12", + "@tanstack/lit-table": "^9.0.0-beta.15", "@tanstack/lit-virtual": "^3.13.29", "lit": "^3.3.3" }, diff --git a/examples/preact/basic-external-atoms/package.json b/examples/preact/basic-external-atoms/package.json index 7d82ec6504..97b7d73bbd 100644 --- a/examples/preact/basic-external-atoms/package.json +++ b/examples/preact/basic-external-atoms/package.json @@ -14,8 +14,8 @@ "@faker-js/faker": "^10.4.0", "@tanstack/preact-devtools": "^0.10.5", "@tanstack/preact-store": "^0.13.1", - "@tanstack/preact-table": "^9.0.0-beta.12", - "@tanstack/preact-table-devtools": "^9.0.0-beta.12", + "@tanstack/preact-table": "^9.0.0-beta.15", + "@tanstack/preact-table-devtools": "^9.0.0-beta.15", "preact": "^10.29.2" }, "devDependencies": { diff --git a/examples/preact/basic-external-state/package.json b/examples/preact/basic-external-state/package.json index 1a4fdd598b..468e985087 100644 --- a/examples/preact/basic-external-state/package.json +++ b/examples/preact/basic-external-state/package.json @@ -14,8 +14,8 @@ "@faker-js/faker": "^10.4.0", "@tanstack/preact-devtools": "^0.10.5", "@tanstack/preact-store": "^0.13.1", - "@tanstack/preact-table": "^9.0.0-beta.12", - "@tanstack/preact-table-devtools": "^9.0.0-beta.12", + "@tanstack/preact-table": "^9.0.0-beta.15", + "@tanstack/preact-table-devtools": "^9.0.0-beta.15", "preact": "^10.29.2" }, "devDependencies": { diff --git a/examples/preact/basic-subscribe/package.json b/examples/preact/basic-subscribe/package.json index 4840049569..6716463eab 100644 --- a/examples/preact/basic-subscribe/package.json +++ b/examples/preact/basic-subscribe/package.json @@ -14,8 +14,8 @@ "@faker-js/faker": "^10.4.0", "@tanstack/preact-devtools": "^0.10.5", "@tanstack/preact-store": "^0.13.1", - "@tanstack/preact-table": "^9.0.0-beta.12", - "@tanstack/preact-table-devtools": "^9.0.0-beta.12", + "@tanstack/preact-table": "^9.0.0-beta.15", + "@tanstack/preact-table-devtools": "^9.0.0-beta.15", "preact": "^10.29.2" }, "devDependencies": { diff --git a/examples/preact/basic-use-app-table/package.json b/examples/preact/basic-use-app-table/package.json index 3a64a628b9..540d68ea4e 100644 --- a/examples/preact/basic-use-app-table/package.json +++ b/examples/preact/basic-use-app-table/package.json @@ -12,8 +12,8 @@ }, "dependencies": { "@tanstack/preact-devtools": "^0.10.5", - "@tanstack/preact-table": "^9.0.0-beta.12", - "@tanstack/preact-table-devtools": "^9.0.0-beta.12", + "@tanstack/preact-table": "^9.0.0-beta.15", + "@tanstack/preact-table-devtools": "^9.0.0-beta.15", "preact": "^10.29.2" }, "devDependencies": { diff --git a/examples/preact/basic-use-table/package.json b/examples/preact/basic-use-table/package.json index 51d63b9c27..8c56fd11e1 100644 --- a/examples/preact/basic-use-table/package.json +++ b/examples/preact/basic-use-table/package.json @@ -12,8 +12,8 @@ }, "dependencies": { "@tanstack/preact-devtools": "^0.10.5", - "@tanstack/preact-table": "^9.0.0-beta.12", - "@tanstack/preact-table-devtools": "^9.0.0-beta.12", + "@tanstack/preact-table": "^9.0.0-beta.15", + "@tanstack/preact-table-devtools": "^9.0.0-beta.15", "preact": "^10.29.2" }, "devDependencies": { diff --git a/examples/preact/column-groups/package.json b/examples/preact/column-groups/package.json index 1a58fc8b32..7ecb064d94 100644 --- a/examples/preact/column-groups/package.json +++ b/examples/preact/column-groups/package.json @@ -12,7 +12,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/preact-table": "^9.0.0-beta.12", + "@tanstack/preact-table": "^9.0.0-beta.15", "preact": "^10.29.2" }, "devDependencies": { diff --git a/examples/preact/column-ordering/package.json b/examples/preact/column-ordering/package.json index 5b3565cb60..b30456c8f3 100644 --- a/examples/preact/column-ordering/package.json +++ b/examples/preact/column-ordering/package.json @@ -12,7 +12,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/preact-table": "^9.0.0-beta.12", + "@tanstack/preact-table": "^9.0.0-beta.15", "preact": "^10.29.2" }, "devDependencies": { diff --git a/examples/preact/column-pinning-split/package.json b/examples/preact/column-pinning-split/package.json index 06028261ed..65f876cbe0 100644 --- a/examples/preact/column-pinning-split/package.json +++ b/examples/preact/column-pinning-split/package.json @@ -12,7 +12,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/preact-table": "^9.0.0-beta.12", + "@tanstack/preact-table": "^9.0.0-beta.15", "preact": "^10.29.2" }, "devDependencies": { diff --git a/examples/preact/column-pinning-sticky/package.json b/examples/preact/column-pinning-sticky/package.json index 57a53d03c3..d08152a2f9 100644 --- a/examples/preact/column-pinning-sticky/package.json +++ b/examples/preact/column-pinning-sticky/package.json @@ -12,7 +12,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/preact-table": "^9.0.0-beta.12", + "@tanstack/preact-table": "^9.0.0-beta.15", "preact": "^10.29.2" }, "devDependencies": { diff --git a/examples/preact/column-pinning/package.json b/examples/preact/column-pinning/package.json index f3622638f9..56b65da8b4 100644 --- a/examples/preact/column-pinning/package.json +++ b/examples/preact/column-pinning/package.json @@ -12,7 +12,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/preact-table": "^9.0.0-beta.12", + "@tanstack/preact-table": "^9.0.0-beta.15", "preact": "^10.29.2" }, "devDependencies": { diff --git a/examples/preact/column-resizing-performant/package.json b/examples/preact/column-resizing-performant/package.json index b426c7568f..f0b27c9953 100644 --- a/examples/preact/column-resizing-performant/package.json +++ b/examples/preact/column-resizing-performant/package.json @@ -12,7 +12,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/preact-table": "^9.0.0-beta.12", + "@tanstack/preact-table": "^9.0.0-beta.15", "preact": "^10.29.2" }, "devDependencies": { diff --git a/examples/preact/column-resizing/package.json b/examples/preact/column-resizing/package.json index 9824166984..9645a21b07 100644 --- a/examples/preact/column-resizing/package.json +++ b/examples/preact/column-resizing/package.json @@ -12,7 +12,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/preact-table": "^9.0.0-beta.12", + "@tanstack/preact-table": "^9.0.0-beta.15", "preact": "^10.29.2" }, "devDependencies": { diff --git a/examples/preact/column-sizing/package.json b/examples/preact/column-sizing/package.json index 46987fe1e3..e3ce276b70 100644 --- a/examples/preact/column-sizing/package.json +++ b/examples/preact/column-sizing/package.json @@ -12,7 +12,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/preact-table": "^9.0.0-beta.12", + "@tanstack/preact-table": "^9.0.0-beta.15", "preact": "^10.29.2" }, "devDependencies": { diff --git a/examples/preact/column-visibility/package.json b/examples/preact/column-visibility/package.json index 6837ecdf8e..7f2f9475f4 100644 --- a/examples/preact/column-visibility/package.json +++ b/examples/preact/column-visibility/package.json @@ -12,7 +12,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/preact-table": "^9.0.0-beta.12", + "@tanstack/preact-table": "^9.0.0-beta.15", "preact": "^10.29.2" }, "devDependencies": { diff --git a/examples/preact/composable-tables/package.json b/examples/preact/composable-tables/package.json index b55ebe42dc..0b30a01bf0 100644 --- a/examples/preact/composable-tables/package.json +++ b/examples/preact/composable-tables/package.json @@ -14,8 +14,8 @@ "@faker-js/faker": "^10.4.0", "@tanstack/preact-devtools": "^0.10.5", "@tanstack/preact-store": "^0.13.1", - "@tanstack/preact-table": "^9.0.0-beta.12", - "@tanstack/preact-table-devtools": "^9.0.0-beta.12", + "@tanstack/preact-table": "^9.0.0-beta.15", + "@tanstack/preact-table-devtools": "^9.0.0-beta.15", "preact": "^10.29.2" }, "devDependencies": { diff --git a/examples/preact/composable-tables/src/components/cell-components.tsx b/examples/preact/composable-tables/src/components/cell-components.tsx index 29c0c22ee9..ebd1d03de0 100644 --- a/examples/preact/composable-tables/src/components/cell-components.tsx +++ b/examples/preact/composable-tables/src/components/cell-components.tsx @@ -5,6 +5,29 @@ * in AppCell children, e.g., */ import { useCellContext } from '../hooks/table' +import { IndeterminateCheckbox } from './indeterminate-checkbox' + +/** + * Row-selection checkbox cell - toggles selection for the current row. + * + * Unlike React (which needs a `Subscribe` boundary to work around React + * Compiler memoization), Preact re-renders this cell when selection state + * changes via the parent table's subscription, so reading `row.getIsSelected()` + * directly is enough. + */ +export function SelectCell() { + const cell = useCellContext() + const row = cell.row + + return ( + + ) +} /** * Generic text cell renderer diff --git a/examples/preact/composable-tables/src/components/indeterminate-checkbox.tsx b/examples/preact/composable-tables/src/components/indeterminate-checkbox.tsx new file mode 100644 index 0000000000..5f0fa43f57 --- /dev/null +++ b/examples/preact/composable-tables/src/components/indeterminate-checkbox.tsx @@ -0,0 +1,39 @@ +/** + * Indeterminate checkbox used by the row-selection column + * (both the select-all header and the per-row select cell). + */ +import { useEffect, useRef } from 'preact/hooks' + +export function IndeterminateCheckbox({ + indeterminate, + className = '', + checked, + onChange, + disabled, + ...rest +}: { + indeterminate?: boolean + checked?: boolean + disabled?: boolean + onChange?: (event: Event) => void +} & Record) { + const ref = useRef(null!) + + useEffect(() => { + if (typeof indeterminate === 'boolean') { + ref.current.indeterminate = !checked && indeterminate + } + }, [ref, indeterminate, checked]) + + return ( + + ) +} diff --git a/examples/preact/composable-tables/src/hooks/table.ts b/examples/preact/composable-tables/src/hooks/table.ts index 49cc16891d..7d5a6a906f 100644 --- a/examples/preact/composable-tables/src/hooks/table.ts +++ b/examples/preact/composable-tables/src/hooks/table.ts @@ -13,6 +13,7 @@ import { createTableHook, filterFns, rowPaginationFeature, + rowSelectionFeature, rowSortingFeature, sortFns, tableFeatures, @@ -32,6 +33,7 @@ import { PriceCell, ProgressCell, RowActionsCell, + SelectCell, StatusCell, TextCell, } from '../components/cell-components' @@ -64,6 +66,7 @@ export const { features: tableFeatures({ columnFilteringFeature, rowPaginationFeature, + rowSelectionFeature, rowSortingFeature, sortedRowModel: createSortedRowModel(), filteredRowModel: createFilteredRowModel(), @@ -84,6 +87,7 @@ export const { // Register cell-level components (accessible via cell.ComponentName in AppCell) cellComponents: { + SelectCell, TextCell, NumberCell, StatusCell, diff --git a/examples/preact/composable-tables/src/index.css b/examples/preact/composable-tables/src/index.css index 4d8fef0142..521b9c190c 100644 --- a/examples/preact/composable-tables/src/index.css +++ b/examples/preact/composable-tables/src/index.css @@ -43,6 +43,21 @@ tfoot th { border-spacing: 0; } +/* Fixed-height, scrollable region around the table. With a page size larger + than ~12 rows the body overflows and scrolls; this is what makes any + remounting of the App wrappers visible (the scroll position would reset). */ +.table-scroll { + max-height: 400px; + overflow: auto; + border: 1px solid lightgray; +} + +.table-scroll thead th { + position: sticky; + top: 0; + z-index: 1; +} + .pagination { display: flex; align-items: center; diff --git a/examples/preact/composable-tables/src/main.tsx b/examples/preact/composable-tables/src/main.tsx index 5792f91e3c..2ebac34597 100644 --- a/examples/preact/composable-tables/src/main.tsx +++ b/examples/preact/composable-tables/src/main.tsx @@ -6,6 +6,7 @@ import { useTanStackTableDevtools, } from '@tanstack/preact-table-devtools' import { createAppColumnHelper, useAppTable } from './hooks/table' +import { IndeterminateCheckbox } from './components/indeterminate-checkbox' import { makeData, makeProductData } from './makeData' import type { Person, Product } from './makeData' import './index.css' @@ -34,6 +35,18 @@ function UsersTable() { () => // NOTE: You must use `createAppColumnHelper` instead of `createColumnHelper` when using pre-bound components like personColumnHelper.columns([ + personColumnHelper.display({ + id: 'select', + header: ({ table }) => ( + + ), + // Cell uses the pre-bound SelectCell component via AppCell + cell: ({ cell }) => , + }), personColumnHelper.accessor('firstName', { header: 'First Name', footer: (props) => props.column.id, @@ -80,6 +93,7 @@ function UsersTable() { columns, data, debugTable: true, + enableRowSelection: true, // more table options }, (state) => state, // default selector @@ -106,112 +120,118 @@ function UsersTable() { onStressTest={stressTest} /> - {/* Table element */} - - - {table.getHeaderGroups().map((headerGroup) => ( - - {headerGroup.headers.map((h) => ( - - {(header) => ( - - )} - - ))} - - ))} - - - {table.getRowModel().rows.map((row) => ( - - {row.getAllCells().map((c) => ( - - {(cell) => ( - - )} - - ))} - - ))} - - - {table.getFooterGroups().map((footerGroup) => ( - - {footerGroup.headers.map((f) => ( - - {(footer) => { - const columnId = footer.column.id - const hasFilter = columnFilters.some( - (cf) => cf.id === columnId, - ) - - return ( - + ))} + + + {table.getFooterGroups().map((footerGroup) => ( + + {footerGroup.headers.map((f) => ( + + {(footer) => { + const columnId = footer.column.id + const hasFilter = columnFilters.some( + (cf) => cf.id === columnId, + ) + + return ( + + ) + }} + + ))} + + ))} + +
- {header.isPlaceholder ? null : ( - <> - - - - {/* Show sort order number when multiple columns sorted */} - {sorting.length > 1 && - sorting.findIndex( - (s) => s.id === header.column.id, - ) > -1 && ( - - {sorting.findIndex( - (s) => s.id === header.column.id, - ) + 1} - - )} - - )} -
- {/* Cell components are pre-bound via AppCell */} - -
- {footer.isPlaceholder ? null : ( + {/* Scroll container with a fixed max-height so larger page sizes + scroll. If the App wrappers remount on state updates, the scroll + position jumps back to the top on every keystroke/selection. */} +
+ + + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((h) => ( + + {(header) => ( + + )} + + ))} + + ))} + + + {table.getRowModel().rows.map((row) => ( + + {row.getAllCells().map((c) => ( + + {(cell) => ( + - ) - }} - - ))} - - ))} - -
+ {header.isPlaceholder ? null : ( <> - {/* Use FooterSum for numeric columns, FooterColumnId for others */} - {columnId === 'age' || - columnId === 'visits' || - columnId === 'progress' ? ( - <> - - {hasFilter && ( - - {' '} - (filtered) - - )} - - ) : columnId === 'actions' ? null : ( - <> - - {hasFilter && ( - - {' '} - ✓ - - )} - - )} + + + + {/* Show sort order number when multiple columns sorted */} + {sorting.length > 1 && + sorting.findIndex( + (s) => s.id === header.column.id, + ) > -1 && ( + + {sorting.findIndex( + (s) => s.id === header.column.id, + ) + 1} + + )} )} +
+ {/* Cell components are pre-bound via AppCell */} +
+ )} + + ))} +
+ {footer.isPlaceholder ? null : ( + <> + {/* Use FooterSum for numeric columns, FooterColumnId for others */} + {columnId === 'age' || + columnId === 'visits' || + columnId === 'progress' ? ( + <> + + {hasFilter && ( + + {' '} + (filtered) + + )} + + ) : columnId === 'actions' ? null : ( + <> + + {hasFilter && ( + + {' '} + ✓ + + )} + + )} + + )} +
+ {/* Pagination using pre-bound component */} @@ -242,6 +262,18 @@ function ProductsTable() { const columns = useMemo( () => productColumnHelper.columns([ + productColumnHelper.display({ + id: 'select', + header: ({ table }) => ( + + ), + // Cell uses the pre-bound SelectCell component via AppCell + cell: ({ cell }) => , + }), productColumnHelper.accessor('name', { header: 'Product Name', footer: (props) => props.column.id, @@ -279,6 +311,7 @@ function ProductsTable() { columns, data, getRowId: (row) => row.id, + enableRowSelection: true, }, (state) => state, // default selector ) @@ -302,111 +335,117 @@ function ProductsTable() { onStressTest={stressTest} /> - {/* Table element */} - - - {table.getHeaderGroups().map((headerGroup) => ( - - {headerGroup.headers.map((h) => ( - - {(header) => ( - - )} - - ))} - - ))} - - - {table.getRowModel().rows.map((row) => ( - - {row.getAllCells().map((c) => ( - - {(cell) => ( - - )} - - ))} - - ))} - - - {table.getFooterGroups().map((footerGroup) => ( - - {footerGroup.headers.map((f) => ( - - {(footer) => { - const columnId = footer.column.id - const hasFilter = columnFilters.some( - (cf) => cf.id === columnId, - ) - - return ( - + ))} + + + {table.getFooterGroups().map((footerGroup) => ( + + {footerGroup.headers.map((f) => ( + + {(footer) => { + const columnId = footer.column.id + const hasFilter = columnFilters.some( + (cf) => cf.id === columnId, + ) + + return ( + + ) + }} + + ))} + + ))} + +
- {header.isPlaceholder ? null : ( - <> - - - - {sorting.length > 1 && - sorting.findIndex( - (s) => s.id === header.column.id, - ) > -1 && ( - - {sorting.findIndex( - (s) => s.id === header.column.id, - ) + 1} - - )} - - )} -
- {/* Cell components are pre-bound via AppCell */} - -
- {footer.isPlaceholder ? null : ( + {/* Scroll container with a fixed max-height so larger page sizes + scroll. If the App wrappers remount on state updates, the scroll + position jumps back to the top on every keystroke/selection. */} +
+ + + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((h) => ( + + {(header) => ( + + )} + + ))} + + ))} + + + {table.getRowModel().rows.map((row) => ( + + {row.getAllCells().map((c) => ( + + {(cell) => ( + - ) - }} - - ))} - - ))} - -
+ {header.isPlaceholder ? null : ( <> - {/* Use FooterSum for numeric columns, FooterColumnId for others */} - {columnId === 'price' || - columnId === 'stock' || - columnId === 'rating' ? ( - <> - - {hasFilter && ( - - {' '} - (filtered) - - )} - - ) : ( - <> - - {hasFilter && ( - - {' '} - ✓ - - )} - - )} + + + + {sorting.length > 1 && + sorting.findIndex( + (s) => s.id === header.column.id, + ) > -1 && ( + + {sorting.findIndex( + (s) => s.id === header.column.id, + ) + 1} + + )} )} +
+ {/* Cell components are pre-bound via AppCell */} +
+ )} + + ))} +
+ {footer.isPlaceholder ? null : ( + <> + {/* Use FooterSum for numeric columns, FooterColumnId for others */} + {columnId === 'price' || + columnId === 'stock' || + columnId === 'rating' ? ( + <> + + {hasFilter && ( + + {' '} + (filtered) + + )} + + ) : ( + <> + + {hasFilter && ( + + {' '} + ✓ + + )} + + )} + + )} +
+ {/* Pagination using the same pre-bound component */} diff --git a/examples/preact/custom-plugin/package.json b/examples/preact/custom-plugin/package.json index 80fe92f9e9..49a4eba33c 100644 --- a/examples/preact/custom-plugin/package.json +++ b/examples/preact/custom-plugin/package.json @@ -12,7 +12,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/preact-table": "^9.0.0-beta.12", + "@tanstack/preact-table": "^9.0.0-beta.15", "preact": "^10.29.2" }, "devDependencies": { diff --git a/examples/preact/expanding/package.json b/examples/preact/expanding/package.json index 42db4dbdaa..c527b0329c 100644 --- a/examples/preact/expanding/package.json +++ b/examples/preact/expanding/package.json @@ -12,7 +12,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/preact-table": "^9.0.0-beta.12", + "@tanstack/preact-table": "^9.0.0-beta.15", "preact": "^10.29.2" }, "devDependencies": { diff --git a/examples/preact/filters-faceted/package.json b/examples/preact/filters-faceted/package.json index 1b225d5012..8fc7324a77 100644 --- a/examples/preact/filters-faceted/package.json +++ b/examples/preact/filters-faceted/package.json @@ -14,7 +14,7 @@ "@faker-js/faker": "^10.4.0", "@tanstack/match-sorter-utils": "^9.0.0-beta.0", "@tanstack/preact-pacer": "^0.22.1", - "@tanstack/preact-table": "^9.0.0-beta.12", + "@tanstack/preact-table": "^9.0.0-beta.15", "preact": "^10.29.2" }, "devDependencies": { diff --git a/examples/preact/filters-fuzzy/package.json b/examples/preact/filters-fuzzy/package.json index 30854fe13b..e29ad0a04a 100644 --- a/examples/preact/filters-fuzzy/package.json +++ b/examples/preact/filters-fuzzy/package.json @@ -14,7 +14,7 @@ "@faker-js/faker": "^10.4.0", "@tanstack/match-sorter-utils": "^9.0.0-beta.0", "@tanstack/preact-pacer": "^0.22.1", - "@tanstack/preact-table": "^9.0.0-beta.12", + "@tanstack/preact-table": "^9.0.0-beta.15", "preact": "^10.29.2" }, "devDependencies": { diff --git a/examples/preact/filters/package.json b/examples/preact/filters/package.json index a778c75346..e8510e0724 100644 --- a/examples/preact/filters/package.json +++ b/examples/preact/filters/package.json @@ -14,7 +14,7 @@ "@faker-js/faker": "^10.4.0", "@tanstack/match-sorter-utils": "^9.0.0-beta.0", "@tanstack/preact-pacer": "^0.22.1", - "@tanstack/preact-table": "^9.0.0-beta.12", + "@tanstack/preact-table": "^9.0.0-beta.15", "preact": "^10.29.2" }, "devDependencies": { diff --git a/examples/preact/grouping/package.json b/examples/preact/grouping/package.json index 941de45419..ed6825b316 100644 --- a/examples/preact/grouping/package.json +++ b/examples/preact/grouping/package.json @@ -12,7 +12,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/preact-table": "^9.0.0-beta.12", + "@tanstack/preact-table": "^9.0.0-beta.15", "preact": "^10.29.2" }, "devDependencies": { diff --git a/examples/preact/kitchen-sink/package.json b/examples/preact/kitchen-sink/package.json index 7fc9297d54..8c3459b097 100644 --- a/examples/preact/kitchen-sink/package.json +++ b/examples/preact/kitchen-sink/package.json @@ -14,8 +14,8 @@ "@faker-js/faker": "^10.4.0", "@tanstack/match-sorter-utils": "^9.0.0-beta.0", "@tanstack/preact-devtools": "^0.10.5", - "@tanstack/preact-table": "^9.0.0-beta.12", - "@tanstack/preact-table-devtools": "^9.0.0-beta.12", + "@tanstack/preact-table": "^9.0.0-beta.15", + "@tanstack/preact-table-devtools": "^9.0.0-beta.15", "preact": "^10.29.2" }, "devDependencies": { diff --git a/examples/preact/pagination/package.json b/examples/preact/pagination/package.json index 7db57901d2..459e47dd75 100644 --- a/examples/preact/pagination/package.json +++ b/examples/preact/pagination/package.json @@ -13,7 +13,7 @@ "dependencies": { "@faker-js/faker": "^10.4.0", "@tanstack/preact-store": "^0.13.1", - "@tanstack/preact-table": "^9.0.0-beta.12", + "@tanstack/preact-table": "^9.0.0-beta.15", "preact": "^10.29.2" }, "devDependencies": { diff --git a/examples/preact/row-pinning/package.json b/examples/preact/row-pinning/package.json index 7e5bd48a76..ddf0af8d28 100644 --- a/examples/preact/row-pinning/package.json +++ b/examples/preact/row-pinning/package.json @@ -12,7 +12,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/preact-table": "^9.0.0-beta.12", + "@tanstack/preact-table": "^9.0.0-beta.15", "preact": "^10.29.2" }, "devDependencies": { diff --git a/examples/preact/row-selection/package.json b/examples/preact/row-selection/package.json index 9d0f444839..c0b4663200 100644 --- a/examples/preact/row-selection/package.json +++ b/examples/preact/row-selection/package.json @@ -14,8 +14,8 @@ "@faker-js/faker": "^10.4.0", "@tanstack/preact-devtools": "^0.10.5", "@tanstack/preact-store": "^0.13.1", - "@tanstack/preact-table": "^9.0.0-beta.12", - "@tanstack/preact-table-devtools": "^9.0.0-beta.12", + "@tanstack/preact-table": "^9.0.0-beta.15", + "@tanstack/preact-table-devtools": "^9.0.0-beta.15", "preact": "^10.29.2" }, "devDependencies": { diff --git a/examples/preact/sorting/package.json b/examples/preact/sorting/package.json index de23b5571e..e60e4c8593 100644 --- a/examples/preact/sorting/package.json +++ b/examples/preact/sorting/package.json @@ -12,7 +12,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/preact-table": "^9.0.0-beta.12", + "@tanstack/preact-table": "^9.0.0-beta.15", "preact": "^10.29.2" }, "devDependencies": { diff --git a/examples/preact/sub-components/package.json b/examples/preact/sub-components/package.json index ddb3441e8f..3d0fe9cfa0 100644 --- a/examples/preact/sub-components/package.json +++ b/examples/preact/sub-components/package.json @@ -12,7 +12,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/preact-table": "^9.0.0-beta.12", + "@tanstack/preact-table": "^9.0.0-beta.15", "preact": "^10.29.2" }, "devDependencies": { diff --git a/examples/preact/with-tanstack-query/package.json b/examples/preact/with-tanstack-query/package.json index b0760d299f..7b99ce93f7 100644 --- a/examples/preact/with-tanstack-query/package.json +++ b/examples/preact/with-tanstack-query/package.json @@ -14,7 +14,7 @@ "@faker-js/faker": "^10.4.0", "@tanstack/preact-query": "^5.101.0", "@tanstack/preact-store": "^0.13.1", - "@tanstack/preact-table": "^9.0.0-beta.12", + "@tanstack/preact-table": "^9.0.0-beta.15", "preact": "^10.29.2" }, "devDependencies": { diff --git a/examples/react/basic-external-atoms/package.json b/examples/react/basic-external-atoms/package.json index 452bbf6e62..ea47471cab 100644 --- a/examples/react/basic-external-atoms/package.json +++ b/examples/react/basic-external-atoms/package.json @@ -13,8 +13,8 @@ "@faker-js/faker": "^10.4.0", "@tanstack/react-devtools": "^0.10.5", "@tanstack/react-store": "^0.11.0", - "@tanstack/react-table": "^9.0.0-beta.12", - "@tanstack/react-table-devtools": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", + "@tanstack/react-table-devtools": "^9.0.0-beta.15", "react": "^19.2.7", "react-dom": "^19.2.7" }, diff --git a/examples/react/basic-external-state/package.json b/examples/react/basic-external-state/package.json index 59e0b9bd9f..39b28baccd 100644 --- a/examples/react/basic-external-state/package.json +++ b/examples/react/basic-external-state/package.json @@ -13,8 +13,8 @@ "@faker-js/faker": "^10.4.0", "@tanstack/react-devtools": "^0.10.5", "@tanstack/react-store": "^0.11.0", - "@tanstack/react-table": "^9.0.0-beta.12", - "@tanstack/react-table-devtools": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", + "@tanstack/react-table-devtools": "^9.0.0-beta.15", "react": "^19.2.7", "react-dom": "^19.2.7" }, diff --git a/examples/react/basic-subscribe/package.json b/examples/react/basic-subscribe/package.json index 69718800ab..ffc1c6cd50 100644 --- a/examples/react/basic-subscribe/package.json +++ b/examples/react/basic-subscribe/package.json @@ -14,8 +14,8 @@ "@tanstack/react-devtools": "^0.10.5", "@tanstack/react-pacer": "^0.22.1", "@tanstack/react-store": "^0.11.0", - "@tanstack/react-table": "^9.0.0-beta.12", - "@tanstack/react-table-devtools": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", + "@tanstack/react-table-devtools": "^9.0.0-beta.15", "react": "^19.2.7", "react-dom": "^19.2.7" }, diff --git a/examples/react/basic-use-app-table/package.json b/examples/react/basic-use-app-table/package.json index 81cfaa125f..65cfdaa794 100644 --- a/examples/react/basic-use-app-table/package.json +++ b/examples/react/basic-use-app-table/package.json @@ -11,8 +11,8 @@ }, "dependencies": { "@tanstack/react-devtools": "^0.10.5", - "@tanstack/react-table": "^9.0.0-beta.12", - "@tanstack/react-table-devtools": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", + "@tanstack/react-table-devtools": "^9.0.0-beta.15", "react": "^19.2.7", "react-dom": "^19.2.7" }, diff --git a/examples/react/basic-use-legacy-table/package.json b/examples/react/basic-use-legacy-table/package.json index 1b4dfaa1ae..682b10edea 100644 --- a/examples/react/basic-use-legacy-table/package.json +++ b/examples/react/basic-use-legacy-table/package.json @@ -13,8 +13,8 @@ "@faker-js/faker": "^10.4.0", "@tanstack/react-devtools": "^0.10.5", "@tanstack/react-pacer": "^0.22.1", - "@tanstack/react-table": "^9.0.0-beta.12", - "@tanstack/react-table-devtools": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", + "@tanstack/react-table-devtools": "^9.0.0-beta.15", "react": "^19.2.7", "react-dom": "^19.2.7" }, diff --git a/examples/react/basic-use-table/package.json b/examples/react/basic-use-table/package.json index a950870114..6d262fed18 100644 --- a/examples/react/basic-use-table/package.json +++ b/examples/react/basic-use-table/package.json @@ -11,8 +11,8 @@ }, "dependencies": { "@tanstack/react-devtools": "^0.10.5", - "@tanstack/react-table": "^9.0.0-beta.12", - "@tanstack/react-table-devtools": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", + "@tanstack/react-table-devtools": "^9.0.0-beta.15", "react": "^19.2.7", "react-dom": "^19.2.7" }, diff --git a/examples/react/column-dnd/package.json b/examples/react/column-dnd/package.json index c1e9f1d778..e0361f996b 100644 --- a/examples/react/column-dnd/package.json +++ b/examples/react/column-dnd/package.json @@ -15,7 +15,7 @@ "@dnd-kit/sortable": "^10.0.0", "@dnd-kit/utilities": "^3.2.2", "@faker-js/faker": "^10.4.0", - "@tanstack/react-table": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", "react": "^19.2.7", "react-dom": "^19.2.7" }, diff --git a/examples/react/column-groups/package.json b/examples/react/column-groups/package.json index 7962e3ffd4..55785ad39f 100644 --- a/examples/react/column-groups/package.json +++ b/examples/react/column-groups/package.json @@ -11,7 +11,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/react-table": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", "react": "^19.2.7", "react-dom": "^19.2.7" }, diff --git a/examples/react/column-ordering/package.json b/examples/react/column-ordering/package.json index f00f840759..394a3a2a82 100644 --- a/examples/react/column-ordering/package.json +++ b/examples/react/column-ordering/package.json @@ -11,7 +11,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/react-table": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", "react": "^19.2.7", "react-dom": "^19.2.7" }, diff --git a/examples/react/column-pinning-split/package.json b/examples/react/column-pinning-split/package.json index 1bcd893b26..cf1b8aa241 100644 --- a/examples/react/column-pinning-split/package.json +++ b/examples/react/column-pinning-split/package.json @@ -11,7 +11,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/react-table": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", "react": "^19.2.7", "react-dom": "^19.2.7" }, diff --git a/examples/react/column-pinning-sticky/package.json b/examples/react/column-pinning-sticky/package.json index dc37710fbc..79bc40dcf8 100644 --- a/examples/react/column-pinning-sticky/package.json +++ b/examples/react/column-pinning-sticky/package.json @@ -11,7 +11,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/react-table": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", "react": "^19.2.7", "react-dom": "^19.2.7" }, diff --git a/examples/react/column-pinning/package.json b/examples/react/column-pinning/package.json index aaadcb9cba..bae05cbdd4 100644 --- a/examples/react/column-pinning/package.json +++ b/examples/react/column-pinning/package.json @@ -11,7 +11,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/react-table": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", "react": "^19.2.7", "react-dom": "^19.2.7" }, diff --git a/examples/react/column-resizing-performant/package.json b/examples/react/column-resizing-performant/package.json index 579be70334..994550bd8e 100644 --- a/examples/react/column-resizing-performant/package.json +++ b/examples/react/column-resizing-performant/package.json @@ -11,7 +11,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/react-table": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", "react": "^19.2.7", "react-dom": "^19.2.7" }, diff --git a/examples/react/column-resizing/package.json b/examples/react/column-resizing/package.json index 3ca18b1f43..f465e3e63b 100644 --- a/examples/react/column-resizing/package.json +++ b/examples/react/column-resizing/package.json @@ -11,7 +11,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/react-table": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", "react": "^19.2.7", "react-dom": "^19.2.7" }, diff --git a/examples/react/column-sizing/package.json b/examples/react/column-sizing/package.json index 698fe35172..62c3a1fbc4 100644 --- a/examples/react/column-sizing/package.json +++ b/examples/react/column-sizing/package.json @@ -11,7 +11,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/react-table": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", "react": "^19.2.7", "react-dom": "^19.2.7" }, diff --git a/examples/react/column-visibility/package.json b/examples/react/column-visibility/package.json index 3b5a8a84e0..b2c311f45a 100644 --- a/examples/react/column-visibility/package.json +++ b/examples/react/column-visibility/package.json @@ -11,7 +11,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/react-table": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", "react": "^19.2.7", "react-dom": "^19.2.7" }, diff --git a/examples/react/composable-tables/package.json b/examples/react/composable-tables/package.json index 3875068d8f..519509ba96 100644 --- a/examples/react/composable-tables/package.json +++ b/examples/react/composable-tables/package.json @@ -13,8 +13,8 @@ "@faker-js/faker": "^10.4.0", "@tanstack/react-devtools": "^0.10.5", "@tanstack/react-store": "^0.11.0", - "@tanstack/react-table": "^9.0.0-beta.12", - "@tanstack/react-table-devtools": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", + "@tanstack/react-table-devtools": "^9.0.0-beta.15", "react": "^19.2.7", "react-dom": "^19.2.7" }, diff --git a/examples/react/composable-tables/src/components/cell-components.tsx b/examples/react/composable-tables/src/components/cell-components.tsx index 29c0c22ee9..fb84eeb668 100644 --- a/examples/react/composable-tables/src/components/cell-components.tsx +++ b/examples/react/composable-tables/src/components/cell-components.tsx @@ -4,7 +4,36 @@ * These components can be used via the pre-bound cellComponents * in AppCell children, e.g., */ -import { useCellContext } from '../hooks/table' +import { Subscribe } from '@tanstack/react-table' +import { useCellContext, useTableContext } from '../hooks/table' +import { IndeterminateCheckbox } from './indeterminate-checkbox' + +/** + * Row-selection checkbox cell - toggles selection for the current row. + * + * The `Subscribe` boundary is required to work around React Compiler + * memoization: the checkbox reads `row.getIsSelected()` (a table API call, not + * a prop or hook the compiler can track), so without an explicit subscription + * to the row-selection state it would never re-render when selection changes. + */ +export function SelectCell() { + const cell = useCellContext() + const table = useTableContext() + const row = cell.row + + return ( + + {() => ( + + )} + + ) +} /** * Generic text cell renderer diff --git a/examples/react/composable-tables/src/components/indeterminate-checkbox.tsx b/examples/react/composable-tables/src/components/indeterminate-checkbox.tsx new file mode 100644 index 0000000000..b3cd414cc7 --- /dev/null +++ b/examples/react/composable-tables/src/components/indeterminate-checkbox.tsx @@ -0,0 +1,22 @@ +/** + * Indeterminate checkbox used by the row-selection column + * (both the select-all header and the per-row select cell). + */ +import { useEffect, useRef } from 'react' +import type { HTMLProps } from 'react' + +export function IndeterminateCheckbox({ + indeterminate, + className = '', + ...rest +}: { indeterminate?: boolean } & HTMLProps) { + const ref = useRef(null!) + + useEffect(() => { + if (typeof indeterminate === 'boolean') { + ref.current.indeterminate = !rest.checked && indeterminate + } + }, [ref, indeterminate, rest.checked]) + + return +} diff --git a/examples/react/composable-tables/src/hooks/table.ts b/examples/react/composable-tables/src/hooks/table.ts index e5c218c8f6..028ed4348a 100644 --- a/examples/react/composable-tables/src/hooks/table.ts +++ b/examples/react/composable-tables/src/hooks/table.ts @@ -13,6 +13,7 @@ import { createTableHook, filterFns, rowPaginationFeature, + rowSelectionFeature, rowSortingFeature, sortFns, tableFeatures, @@ -32,6 +33,7 @@ import { PriceCell, ProgressCell, RowActionsCell, + SelectCell, StatusCell, TextCell, } from '../components/cell-components' @@ -64,6 +66,7 @@ export const { features: tableFeatures({ columnFilteringFeature, rowPaginationFeature, + rowSelectionFeature, rowSortingFeature, sortedRowModel: createSortedRowModel(), filteredRowModel: createFilteredRowModel(), @@ -84,6 +87,7 @@ export const { // Register cell-level components (accessible via cell.ComponentName in AppCell) cellComponents: { + SelectCell, TextCell, NumberCell, StatusCell, diff --git a/examples/react/composable-tables/src/index.css b/examples/react/composable-tables/src/index.css index 4d8fef0142..521b9c190c 100644 --- a/examples/react/composable-tables/src/index.css +++ b/examples/react/composable-tables/src/index.css @@ -43,6 +43,21 @@ tfoot th { border-spacing: 0; } +/* Fixed-height, scrollable region around the table. With a page size larger + than ~12 rows the body overflows and scrolls; this is what makes any + remounting of the App wrappers visible (the scroll position would reset). */ +.table-scroll { + max-height: 400px; + overflow: auto; + border: 1px solid lightgray; +} + +.table-scroll thead th { + position: sticky; + top: 0; + z-index: 1; +} + .pagination { display: flex; align-items: center; diff --git a/examples/react/composable-tables/src/main.tsx b/examples/react/composable-tables/src/main.tsx index 3afef5e1a6..20c03c9342 100644 --- a/examples/react/composable-tables/src/main.tsx +++ b/examples/react/composable-tables/src/main.tsx @@ -6,9 +6,12 @@ import { tableDevtoolsPlugin, useTanStackTableDevtools, } from '@tanstack/react-table-devtools' +import { Subscribe } from '@tanstack/react-table' import { createAppColumnHelper, useAppTable } from './hooks/table' +import { IndeterminateCheckbox } from './components/indeterminate-checkbox' import { makeData, makeProductData } from './makeData' import type { Person, Product } from './makeData' +import './index.css' // Import cell components directly - they use useCellContext internally // Create column helpers with TFeatures already bound - only need TData! @@ -34,6 +37,23 @@ function UsersTable() { () => // NOTE: You must use `createAppColumnHelper` instead of `createColumnHelper` when using pre-bound components like personColumnHelper.columns([ + personColumnHelper.display({ + id: 'select', + header: ({ table }) => ( + // Subscribe works around React Compiler memoization (see SelectCell) + + {() => ( + + )} + + ), + // Cell uses the pre-bound SelectCell component via AppCell + cell: ({ cell }) => , + }), personColumnHelper.accessor('firstName', { header: 'First Name', footer: (props) => props.column.id, @@ -80,6 +100,7 @@ function UsersTable() { columns, data, debugTable: true, + enableRowSelection: true, // more table options }, (state) => state, // default selector @@ -105,113 +126,115 @@ function UsersTable() { onRefresh={refreshData} onStressTest={stressTest} /> - - {/* Table element */} - - - {table.getHeaderGroups().map((headerGroup) => ( - - {headerGroup.headers.map((h) => ( - - {(header) => ( - - )} - - ))} - - ))} - - - {table.getRowModel().rows.map((row) => ( - - {row.getAllCells().map((c) => ( - - {(cell) => ( - - )} - - ))} - - ))} - - - {table.getFooterGroups().map((footerGroup) => ( - - {footerGroup.headers.map((f) => ( - - {(footer) => { - const columnId = footer.column.id - const hasFilter = columnFilters.some( - (cf) => cf.id === columnId, - ) - - return ( - + ))} + + + {table.getFooterGroups().map((footerGroup) => ( + + {footerGroup.headers.map((f) => ( + + {(footer) => { + const columnId = footer.column.id + const hasFilter = columnFilters.some( + (cf) => cf.id === columnId, + ) + + return ( + + ) + }} + + ))} + + ))} + +
- {header.isPlaceholder ? null : ( - <> - - - - {/* Show sort order number when multiple columns sorted */} - {sorting.length > 1 && - sorting.findIndex( - (s) => s.id === header.column.id, - ) > -1 && ( - - {sorting.findIndex( - (s) => s.id === header.column.id, - ) + 1} - - )} - - )} -
- {/* Cell components are pre-bound via AppCell */} - -
- {footer.isPlaceholder ? null : ( +
+ + + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((h) => ( + + {(header) => ( + + )} + + ))} + + ))} + + + {table.getRowModel().rows.map((row) => ( + + {row.getAllCells().map((c) => ( + + {(cell) => ( + - ) - }} - - ))} - - ))} - -
+ {header.isPlaceholder ? null : ( <> - {/* Use FooterSum for numeric columns, FooterColumnId for others */} - {columnId === 'age' || - columnId === 'visits' || - columnId === 'progress' ? ( - <> - - {hasFilter && ( - - {' '} - (filtered) - - )} - - ) : columnId === 'actions' ? null : ( - <> - - {hasFilter && ( - - {' '} - ✓ - - )} - - )} + + + + {/* Show sort order number when multiple columns sorted */} + {sorting.length > 1 && + sorting.findIndex( + (s) => s.id === header.column.id, + ) > -1 && ( + + {sorting.findIndex( + (s) => s.id === header.column.id, + ) + 1} + + )} )} +
+ {/* Cell components are pre-bound via AppCell */} +
+ )} + + ))} +
+ {footer.isPlaceholder ? null : ( + <> + {/* Use FooterSum for numeric columns, FooterColumnId for others */} + {columnId === 'age' || + columnId === 'visits' || + columnId === 'progress' ? ( + <> + + {hasFilter && ( + + {' '} + (filtered) + + )} + + ) : columnId === 'actions' ? null : ( + <> + + {hasFilter && ( + + {' '} + ✓ + + )} + + )} + + )} +
+ {/* Pagination using pre-bound component */} @@ -242,6 +265,23 @@ function ProductsTable() { const columns = useMemo( () => productColumnHelper.columns([ + productColumnHelper.display({ + id: 'select', + header: ({ table }) => ( + // Subscribe works around React Compiler memoization (see SelectCell) + + {() => ( + + )} + + ), + // Cell uses the pre-bound SelectCell component via AppCell + cell: ({ cell }) => , + }), productColumnHelper.accessor('name', { header: 'Product Name', footer: (props) => props.column.id, @@ -279,6 +319,7 @@ function ProductsTable() { columns, data, getRowId: (row) => row.id, + enableRowSelection: true, }, (state) => state, // default selector ) @@ -301,112 +342,114 @@ function ProductsTable() { onRefresh={refreshData} onStressTest={stressTest} /> - - {/* Table element */} - - - {table.getHeaderGroups().map((headerGroup) => ( - - {headerGroup.headers.map((h) => ( - - {(header) => ( - - )} - - ))} - - ))} - - - {table.getRowModel().rows.map((row) => ( - - {row.getAllCells().map((c) => ( - - {(cell) => ( - - )} - - ))} - - ))} - - - {table.getFooterGroups().map((footerGroup) => ( - - {footerGroup.headers.map((f) => ( - - {(footer) => { - const columnId = footer.column.id - const hasFilter = columnFilters.some( - (cf) => cf.id === columnId, - ) - - return ( - + ))} + + + {table.getFooterGroups().map((footerGroup) => ( + + {footerGroup.headers.map((f) => ( + + {(footer) => { + const columnId = footer.column.id + const hasFilter = columnFilters.some( + (cf) => cf.id === columnId, + ) + + return ( + + ) + }} + + ))} + + ))} + +
- {header.isPlaceholder ? null : ( - <> - - - - {sorting.length > 1 && - sorting.findIndex( - (s) => s.id === header.column.id, - ) > -1 && ( - - {sorting.findIndex( - (s) => s.id === header.column.id, - ) + 1} - - )} - - )} -
- {/* Cell components are pre-bound via AppCell */} - -
- {footer.isPlaceholder ? null : ( +
+ + + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((h) => ( + + {(header) => ( + + )} + + ))} + + ))} + + + {table.getRowModel().rows.map((row) => ( + + {row.getAllCells().map((c) => ( + + {(cell) => ( + - ) - }} - - ))} - - ))} - -
+ {header.isPlaceholder ? null : ( <> - {/* Use FooterSum for numeric columns, FooterColumnId for others */} - {columnId === 'price' || - columnId === 'stock' || - columnId === 'rating' ? ( - <> - - {hasFilter && ( - - {' '} - (filtered) - - )} - - ) : ( - <> - - {hasFilter && ( - - {' '} - ✓ - - )} - - )} + + + + {sorting.length > 1 && + sorting.findIndex( + (s) => s.id === header.column.id, + ) > -1 && ( + + {sorting.findIndex( + (s) => s.id === header.column.id, + ) + 1} + + )} )} +
+ {/* Cell components are pre-bound via AppCell */} +
+ )} + + ))} +
+ {footer.isPlaceholder ? null : ( + <> + {/* Use FooterSum for numeric columns, FooterColumnId for others */} + {columnId === 'price' || + columnId === 'stock' || + columnId === 'rating' ? ( + <> + + {hasFilter && ( + + {' '} + (filtered) + + )} + + ) : ( + <> + + {hasFilter && ( + + {' '} + ✓ + + )} + + )} + + )} +
+ {/* Pagination using the same pre-bound component */} diff --git a/examples/react/custom-plugin/package.json b/examples/react/custom-plugin/package.json index 9f51efa5a2..5a3d2b6aeb 100644 --- a/examples/react/custom-plugin/package.json +++ b/examples/react/custom-plugin/package.json @@ -12,7 +12,7 @@ "dependencies": { "@faker-js/faker": "^10.4.0", "@tanstack/react-pacer": "^0.22.1", - "@tanstack/react-table": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", "react": "^19.2.7", "react-dom": "^19.2.7" }, diff --git a/examples/react/expanding/package.json b/examples/react/expanding/package.json index be33fa8d25..d1d89f7545 100644 --- a/examples/react/expanding/package.json +++ b/examples/react/expanding/package.json @@ -12,7 +12,7 @@ "dependencies": { "@faker-js/faker": "^10.4.0", "@tanstack/react-pacer": "^0.22.1", - "@tanstack/react-table": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", "react": "^19.2.7", "react-dom": "^19.2.7" }, diff --git a/examples/react/filters-faceted/package.json b/examples/react/filters-faceted/package.json index 3dabd32a06..f04d15a6fb 100644 --- a/examples/react/filters-faceted/package.json +++ b/examples/react/filters-faceted/package.json @@ -13,7 +13,7 @@ "@faker-js/faker": "^10.4.0", "@tanstack/match-sorter-utils": "^9.0.0-beta.0", "@tanstack/react-pacer": "^0.22.1", - "@tanstack/react-table": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", "react": "^19.2.7", "react-dom": "^19.2.7" }, diff --git a/examples/react/filters-fuzzy/package.json b/examples/react/filters-fuzzy/package.json index 308bddd681..34b6ac7757 100644 --- a/examples/react/filters-fuzzy/package.json +++ b/examples/react/filters-fuzzy/package.json @@ -13,7 +13,7 @@ "@faker-js/faker": "^10.4.0", "@tanstack/match-sorter-utils": "^9.0.0-beta.0", "@tanstack/react-pacer": "^0.22.1", - "@tanstack/react-table": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", "react": "^19.2.7", "react-dom": "^19.2.7" }, diff --git a/examples/react/filters/package.json b/examples/react/filters/package.json index 31b02d4879..d1b7f066c1 100644 --- a/examples/react/filters/package.json +++ b/examples/react/filters/package.json @@ -13,7 +13,7 @@ "@faker-js/faker": "^10.4.0", "@tanstack/match-sorter-utils": "^9.0.0-beta.0", "@tanstack/react-pacer": "^0.22.1", - "@tanstack/react-table": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", "react": "^19.2.7", "react-dom": "^19.2.7" }, diff --git a/examples/react/grouping/package.json b/examples/react/grouping/package.json index c43e59fe27..a5958da556 100644 --- a/examples/react/grouping/package.json +++ b/examples/react/grouping/package.json @@ -11,7 +11,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/react-table": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", "react": "^19.2.7", "react-dom": "^19.2.7" }, diff --git a/examples/react/kitchen-sink-hero-ui/package.json b/examples/react/kitchen-sink-hero-ui/package.json index 036bbcd918..ba2695246e 100644 --- a/examples/react/kitchen-sink-hero-ui/package.json +++ b/examples/react/kitchen-sink-hero-ui/package.json @@ -22,8 +22,8 @@ "@tanstack/match-sorter-utils": "^9.0.0-beta.0", "@tanstack/react-devtools": "^0.10.5", "@tanstack/react-pacer": "^0.22.1", - "@tanstack/react-table": "^9.0.0-beta.12", - "@tanstack/react-table-devtools": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", + "@tanstack/react-table-devtools": "^9.0.0-beta.15", "date-fns": "^4.4.0", "react": "^19.2.7", "react-dom": "^19.2.7", diff --git a/examples/react/kitchen-sink-mantine/package.json b/examples/react/kitchen-sink-mantine/package.json index 76e1c98c87..5a338be3b9 100644 --- a/examples/react/kitchen-sink-mantine/package.json +++ b/examples/react/kitchen-sink-mantine/package.json @@ -21,8 +21,8 @@ "@tanstack/match-sorter-utils": "^9.0.0-beta.0", "@tanstack/react-devtools": "^0.10.5", "@tanstack/react-pacer": "^0.22.1", - "@tanstack/react-table": "^9.0.0-beta.12", - "@tanstack/react-table-devtools": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", + "@tanstack/react-table-devtools": "^9.0.0-beta.15", "date-fns": "^4.4.0", "react": "^19.2.7", "react-dom": "^19.2.7" diff --git a/examples/react/kitchen-sink-material-ui/package.json b/examples/react/kitchen-sink-material-ui/package.json index 5fbdf209fa..e2e2fe9e67 100644 --- a/examples/react/kitchen-sink-material-ui/package.json +++ b/examples/react/kitchen-sink-material-ui/package.json @@ -22,8 +22,8 @@ "@tanstack/match-sorter-utils": "^9.0.0-beta.0", "@tanstack/react-devtools": "^0.10.5", "@tanstack/react-pacer": "^0.22.1", - "@tanstack/react-table": "^9.0.0-beta.12", - "@tanstack/react-table-devtools": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", + "@tanstack/react-table-devtools": "^9.0.0-beta.15", "date-fns": "^4.4.0", "react": "^19.2.7", "react-dom": "^19.2.7" diff --git a/examples/react/kitchen-sink-react-aria/package.json b/examples/react/kitchen-sink-react-aria/package.json index 5b5c63570d..97fa99f5fe 100644 --- a/examples/react/kitchen-sink-react-aria/package.json +++ b/examples/react/kitchen-sink-react-aria/package.json @@ -20,8 +20,8 @@ "@tanstack/match-sorter-utils": "^9.0.0-beta.0", "@tanstack/react-devtools": "^0.10.5", "@tanstack/react-pacer": "^0.22.1", - "@tanstack/react-table": "^9.0.0-beta.12", - "@tanstack/react-table-devtools": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", + "@tanstack/react-table-devtools": "^9.0.0-beta.15", "date-fns": "^4.4.0", "react": "^19.2.7", "react-aria-components": "^1.18.0", diff --git a/examples/react/kitchen-sink-shadcn-base/package.json b/examples/react/kitchen-sink-shadcn-base/package.json index 2dac629740..83250b3b93 100644 --- a/examples/react/kitchen-sink-shadcn-base/package.json +++ b/examples/react/kitchen-sink-shadcn-base/package.json @@ -22,8 +22,8 @@ "@tanstack/match-sorter-utils": "^9.0.0-beta.0", "@tanstack/react-devtools": "^0.10.5", "@tanstack/react-pacer": "^0.22.1", - "@tanstack/react-table": "^9.0.0-beta.12", - "@tanstack/react-table-devtools": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", + "@tanstack/react-table-devtools": "^9.0.0-beta.15", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "cmdk": "1.1.1", diff --git a/examples/react/kitchen-sink-shadcn-radix/package.json b/examples/react/kitchen-sink-shadcn-radix/package.json index 42063e84bb..da3e4e48c2 100644 --- a/examples/react/kitchen-sink-shadcn-radix/package.json +++ b/examples/react/kitchen-sink-shadcn-radix/package.json @@ -21,8 +21,8 @@ "@tanstack/match-sorter-utils": "^9.0.0-beta.0", "@tanstack/react-devtools": "^0.10.5", "@tanstack/react-pacer": "^0.22.1", - "@tanstack/react-table": "^9.0.0-beta.12", - "@tanstack/react-table-devtools": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", + "@tanstack/react-table-devtools": "^9.0.0-beta.15", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "cmdk": "1.1.1", diff --git a/examples/react/kitchen-sink/package.json b/examples/react/kitchen-sink/package.json index b36fdc198b..8396975b31 100644 --- a/examples/react/kitchen-sink/package.json +++ b/examples/react/kitchen-sink/package.json @@ -19,8 +19,8 @@ "@tanstack/react-devtools": "^0.10.5", "@tanstack/react-pacer": "^0.22.1", "@tanstack/react-store": "^0.11.0", - "@tanstack/react-table": "^9.0.0-beta.12", - "@tanstack/react-table-devtools": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", + "@tanstack/react-table-devtools": "^9.0.0-beta.15", "react": "^19.2.7", "react-dom": "^19.2.7" }, diff --git a/examples/react/lib-hero-ui/package.json b/examples/react/lib-hero-ui/package.json index 574c2b472a..f630ff6063 100644 --- a/examples/react/lib-hero-ui/package.json +++ b/examples/react/lib-hero-ui/package.json @@ -15,7 +15,7 @@ "@heroui/react": "^3.1.0", "@heroui/styles": "^3.1.0", "@tailwindcss/vite": "^4.3.0", - "@tanstack/react-table": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", "react": "^19.2.7", "react-dom": "^19.2.7", "tailwindcss": "^4.3.0" diff --git a/examples/react/lib-mantine/package.json b/examples/react/lib-mantine/package.json index 21761a68b5..a5b6736c39 100644 --- a/examples/react/lib-mantine/package.json +++ b/examples/react/lib-mantine/package.json @@ -15,7 +15,7 @@ "@mantine/core": "^9.3.0", "@mantine/hooks": "^9.3.0", "@tabler/icons-react": "^3.44.0", - "@tanstack/react-table": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", "react": "^19.2.7", "react-dom": "^19.2.7" }, diff --git a/examples/react/lib-material-ui/package.json b/examples/react/lib-material-ui/package.json index e75494d675..d63f328d45 100644 --- a/examples/react/lib-material-ui/package.json +++ b/examples/react/lib-material-ui/package.json @@ -16,7 +16,7 @@ "@faker-js/faker": "^10.4.0", "@mui/icons-material": "^9.0.1", "@mui/material": "^9.0.1", - "@tanstack/react-table": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", "react": "^19.2.7", "react-dom": "^19.2.7" }, diff --git a/examples/react/lib-react-aria/package.json b/examples/react/lib-react-aria/package.json index c253c24dc9..1fcc166fe2 100644 --- a/examples/react/lib-react-aria/package.json +++ b/examples/react/lib-react-aria/package.json @@ -13,7 +13,7 @@ "dependencies": { "@faker-js/faker": "^10.4.0", "@tailwindcss/vite": "^4.3.0", - "@tanstack/react-table": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", "react": "^19.2.7", "react-aria-components": "^1.18.0", "react-dom": "^19.2.7", diff --git a/examples/react/lib-shadcn-base/package.json b/examples/react/lib-shadcn-base/package.json index b82ff91b8e..84a7e2fdf7 100644 --- a/examples/react/lib-shadcn-base/package.json +++ b/examples/react/lib-shadcn-base/package.json @@ -15,7 +15,7 @@ "@faker-js/faker": "^10.4.0", "@tailwindcss/vite": "^4.3.0", "@tanstack/react-pacer": "^0.22.1", - "@tanstack/react-table": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "lucide-react": "^1.17.0", diff --git a/examples/react/lib-shadcn-radix/package.json b/examples/react/lib-shadcn-radix/package.json index 399170d8b9..0979a90742 100644 --- a/examples/react/lib-shadcn-radix/package.json +++ b/examples/react/lib-shadcn-radix/package.json @@ -14,7 +14,7 @@ "@faker-js/faker": "^10.4.0", "@tailwindcss/vite": "^4.3.0", "@tanstack/react-pacer": "^0.22.1", - "@tanstack/react-table": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "lucide-react": "^1.17.0", diff --git a/examples/react/mantine-react-table/package.json b/examples/react/mantine-react-table/package.json index ad8d0a4053..3396f60dcf 100644 --- a/examples/react/mantine-react-table/package.json +++ b/examples/react/mantine-react-table/package.json @@ -17,7 +17,7 @@ "@tabler/icons-react": "^3.44.0", "@tanstack/match-sorter-utils": "^9.0.0-beta.0", "@tanstack/react-store": "^0.11.0", - "@tanstack/react-table": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", "@tanstack/react-virtual": "^3.14.2", "clsx": "^2.1.1", "dayjs": "^1.11.21", diff --git a/examples/react/material-react-table/package.json b/examples/react/material-react-table/package.json index 2b2138513e..bdc7111be1 100644 --- a/examples/react/material-react-table/package.json +++ b/examples/react/material-react-table/package.json @@ -20,7 +20,7 @@ "@tanstack/match-sorter-utils": "^9.0.0-beta.0", "@tanstack/react-pacer": "^0.22.1", "@tanstack/react-store": "^0.11.0", - "@tanstack/react-table": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", "@tanstack/react-virtual": "^3.14.2", "highlight-words": "^2.0.0", "react": "^19.2.7", diff --git a/examples/react/pagination/package.json b/examples/react/pagination/package.json index 1bab6114cf..d93e4dec59 100644 --- a/examples/react/pagination/package.json +++ b/examples/react/pagination/package.json @@ -12,7 +12,7 @@ "dependencies": { "@faker-js/faker": "^10.4.0", "@tanstack/react-store": "^0.11.0", - "@tanstack/react-table": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", "react": "^19.2.7", "react-dom": "^19.2.7" }, diff --git a/examples/react/row-dnd/package.json b/examples/react/row-dnd/package.json index e0cac6d3bd..ce8724eff2 100644 --- a/examples/react/row-dnd/package.json +++ b/examples/react/row-dnd/package.json @@ -15,7 +15,7 @@ "@dnd-kit/sortable": "^10.0.0", "@dnd-kit/utilities": "^3.2.2", "@faker-js/faker": "^10.4.0", - "@tanstack/react-table": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", "react": "^19.2.7", "react-dom": "^19.2.7" }, diff --git a/examples/react/row-pinning/package.json b/examples/react/row-pinning/package.json index d3dc554da9..e8516d8ae4 100644 --- a/examples/react/row-pinning/package.json +++ b/examples/react/row-pinning/package.json @@ -12,7 +12,7 @@ "dependencies": { "@faker-js/faker": "^10.4.0", "@tanstack/react-pacer": "^0.22.1", - "@tanstack/react-table": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", "react": "^19.2.7", "react-dom": "^19.2.7" }, diff --git a/examples/react/row-selection/package.json b/examples/react/row-selection/package.json index 4c0e4cd9fc..878381bc20 100644 --- a/examples/react/row-selection/package.json +++ b/examples/react/row-selection/package.json @@ -14,8 +14,8 @@ "@tanstack/react-devtools": "^0.10.5", "@tanstack/react-pacer": "^0.22.1", "@tanstack/react-store": "^0.11.0", - "@tanstack/react-table": "^9.0.0-beta.12", - "@tanstack/react-table-devtools": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", + "@tanstack/react-table-devtools": "^9.0.0-beta.15", "react": "^19.2.7", "react-dom": "^19.2.7" }, diff --git a/examples/react/sorting/package.json b/examples/react/sorting/package.json index 057e6a44d0..48583443c6 100644 --- a/examples/react/sorting/package.json +++ b/examples/react/sorting/package.json @@ -11,7 +11,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/react-table": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", "react": "^19.2.7", "react-dom": "^19.2.7" }, diff --git a/examples/react/sub-components/package.json b/examples/react/sub-components/package.json index 05dd182f19..a82dd62d54 100644 --- a/examples/react/sub-components/package.json +++ b/examples/react/sub-components/package.json @@ -11,7 +11,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/react-table": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", "react": "^19.2.7", "react-dom": "^19.2.7" }, diff --git a/examples/react/virtualized-columns-experimental/package.json b/examples/react/virtualized-columns-experimental/package.json index 8f6d93b74e..805440229f 100644 --- a/examples/react/virtualized-columns-experimental/package.json +++ b/examples/react/virtualized-columns-experimental/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/react-table": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", "@tanstack/react-virtual": "^3.14.2", "react": "^19.2.7", "react-dom": "^19.2.7" diff --git a/examples/react/virtualized-columns/package.json b/examples/react/virtualized-columns/package.json index 4ec25f4dc4..d4ce60c8f8 100644 --- a/examples/react/virtualized-columns/package.json +++ b/examples/react/virtualized-columns/package.json @@ -11,7 +11,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/react-table": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", "@tanstack/react-virtual": "^3.14.2", "react": "^19.2.7", "react-dom": "^19.2.7" diff --git a/examples/react/virtualized-infinite-scrolling/package.json b/examples/react/virtualized-infinite-scrolling/package.json index 1c3380dfc4..0af5f99ba0 100644 --- a/examples/react/virtualized-infinite-scrolling/package.json +++ b/examples/react/virtualized-infinite-scrolling/package.json @@ -12,7 +12,7 @@ "dependencies": { "@faker-js/faker": "^10.4.0", "@tanstack/react-query": "^5.101.0", - "@tanstack/react-table": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", "@tanstack/react-virtual": "^3.14.2", "react": "^19.2.7", "react-dom": "^19.2.7" diff --git a/examples/react/virtualized-rows-experimental/package.json b/examples/react/virtualized-rows-experimental/package.json index 3bb9cc3a74..ab4a0170bf 100644 --- a/examples/react/virtualized-rows-experimental/package.json +++ b/examples/react/virtualized-rows-experimental/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/react-table": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", "@tanstack/react-virtual": "^3.14.2", "react": "^19.2.7", "react-dom": "^19.2.7" diff --git a/examples/react/virtualized-rows/package.json b/examples/react/virtualized-rows/package.json index 4f95ac04a9..75699c0335 100644 --- a/examples/react/virtualized-rows/package.json +++ b/examples/react/virtualized-rows/package.json @@ -11,7 +11,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/react-table": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", "@tanstack/react-virtual": "^3.14.2", "react": "^19.2.7", "react-dom": "^19.2.7" diff --git a/examples/react/with-tanstack-form/package.json b/examples/react/with-tanstack-form/package.json index 75c66281c4..76510ff0b8 100644 --- a/examples/react/with-tanstack-form/package.json +++ b/examples/react/with-tanstack-form/package.json @@ -13,7 +13,7 @@ "@faker-js/faker": "^10.4.0", "@tanstack/react-form": "^1.33.0", "@tanstack/react-pacer": "^0.22.1", - "@tanstack/react-table": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", "react": "^19.2.7", "react-dom": "^19.2.7", "zod": "^4.4.3" diff --git a/examples/react/with-tanstack-query/package.json b/examples/react/with-tanstack-query/package.json index 9c5259666e..bca3d5532c 100644 --- a/examples/react/with-tanstack-query/package.json +++ b/examples/react/with-tanstack-query/package.json @@ -13,7 +13,7 @@ "@faker-js/faker": "^10.4.0", "@tanstack/react-query": "^5.101.0", "@tanstack/react-store": "^0.11.0", - "@tanstack/react-table": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", "react": "^19.2.7", "react-dom": "^19.2.7" }, diff --git a/examples/react/with-tanstack-router/package.json b/examples/react/with-tanstack-router/package.json index ad398551d9..4cfef15397 100644 --- a/examples/react/with-tanstack-router/package.json +++ b/examples/react/with-tanstack-router/package.json @@ -13,7 +13,7 @@ "@tanstack/react-pacer": "^0.22.1", "@tanstack/react-query": "^5.101.0", "@tanstack/react-router": "^1.170.15", - "@tanstack/react-table": "^9.0.0-beta.12", + "@tanstack/react-table": "^9.0.0-beta.15", "react": "^19.2.7", "react-dom": "^19.2.7" }, diff --git a/examples/solid/basic-app-table/package.json b/examples/solid/basic-app-table/package.json index d24c2781ce..c7bee0aa08 100644 --- a/examples/solid/basic-app-table/package.json +++ b/examples/solid/basic-app-table/package.json @@ -17,8 +17,8 @@ "dependencies": { "@faker-js/faker": "^10.4.0", "@tanstack/solid-devtools": "^0.8.5", - "@tanstack/solid-table": "^9.0.0-beta.12", - "@tanstack/solid-table-devtools": "^9.0.0-beta.12", + "@tanstack/solid-table": "^9.0.0-beta.15", + "@tanstack/solid-table-devtools": "^9.0.0-beta.15", "solid-js": "^1.9.13" } } diff --git a/examples/solid/basic-external-atoms/package.json b/examples/solid/basic-external-atoms/package.json index a46c4e0903..38b61f23e5 100644 --- a/examples/solid/basic-external-atoms/package.json +++ b/examples/solid/basic-external-atoms/package.json @@ -18,8 +18,8 @@ "dependencies": { "@tanstack/solid-devtools": "^0.8.5", "@tanstack/solid-store": "^0.11.0", - "@tanstack/solid-table": "^9.0.0-beta.12", - "@tanstack/solid-table-devtools": "^9.0.0-beta.12", + "@tanstack/solid-table": "^9.0.0-beta.15", + "@tanstack/solid-table-devtools": "^9.0.0-beta.15", "solid-js": "^1.9.13" } } diff --git a/examples/solid/basic-external-state/package.json b/examples/solid/basic-external-state/package.json index 84fb047a2f..81cdef3c02 100644 --- a/examples/solid/basic-external-state/package.json +++ b/examples/solid/basic-external-state/package.json @@ -17,8 +17,8 @@ }, "dependencies": { "@tanstack/solid-devtools": "^0.8.5", - "@tanstack/solid-table": "^9.0.0-beta.12", - "@tanstack/solid-table-devtools": "^9.0.0-beta.12", + "@tanstack/solid-table": "^9.0.0-beta.15", + "@tanstack/solid-table-devtools": "^9.0.0-beta.15", "solid-js": "^1.9.13" } } diff --git a/examples/solid/basic-use-table/package.json b/examples/solid/basic-use-table/package.json index e87bff0991..82fc4603f8 100644 --- a/examples/solid/basic-use-table/package.json +++ b/examples/solid/basic-use-table/package.json @@ -16,8 +16,8 @@ }, "dependencies": { "@tanstack/solid-devtools": "^0.8.5", - "@tanstack/solid-table": "^9.0.0-beta.12", - "@tanstack/solid-table-devtools": "^9.0.0-beta.12", + "@tanstack/solid-table": "^9.0.0-beta.15", + "@tanstack/solid-table-devtools": "^9.0.0-beta.15", "solid-js": "^1.9.13" } } diff --git a/examples/solid/column-groups/package.json b/examples/solid/column-groups/package.json index 455cb0edf2..69ec326120 100644 --- a/examples/solid/column-groups/package.json +++ b/examples/solid/column-groups/package.json @@ -16,7 +16,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/solid-table": "^9.0.0-beta.12", + "@tanstack/solid-table": "^9.0.0-beta.15", "solid-js": "^1.9.13" } } diff --git a/examples/solid/column-ordering/package.json b/examples/solid/column-ordering/package.json index e7fc95d234..b3affe3d3b 100644 --- a/examples/solid/column-ordering/package.json +++ b/examples/solid/column-ordering/package.json @@ -16,7 +16,7 @@ "vite-plugin-solid": "^2.11.12" }, "dependencies": { - "@tanstack/solid-table": "^9.0.0-beta.12", + "@tanstack/solid-table": "^9.0.0-beta.15", "solid-js": "^1.9.13" } } diff --git a/examples/solid/column-pinning-split/package.json b/examples/solid/column-pinning-split/package.json index f1ccc7d2e4..6509cbfad0 100644 --- a/examples/solid/column-pinning-split/package.json +++ b/examples/solid/column-pinning-split/package.json @@ -16,7 +16,7 @@ "vite-plugin-solid": "^2.11.12" }, "dependencies": { - "@tanstack/solid-table": "^9.0.0-beta.12", + "@tanstack/solid-table": "^9.0.0-beta.15", "solid-js": "^1.9.13" } } diff --git a/examples/solid/column-pinning-sticky/package.json b/examples/solid/column-pinning-sticky/package.json index 8bc65e81d3..aff79cbfe1 100644 --- a/examples/solid/column-pinning-sticky/package.json +++ b/examples/solid/column-pinning-sticky/package.json @@ -16,7 +16,7 @@ "vite-plugin-solid": "^2.11.12" }, "dependencies": { - "@tanstack/solid-table": "^9.0.0-beta.12", + "@tanstack/solid-table": "^9.0.0-beta.15", "solid-js": "^1.9.13" } } diff --git a/examples/solid/column-pinning/package.json b/examples/solid/column-pinning/package.json index b363207d10..6043ad67fc 100644 --- a/examples/solid/column-pinning/package.json +++ b/examples/solid/column-pinning/package.json @@ -16,7 +16,7 @@ "vite-plugin-solid": "^2.11.12" }, "dependencies": { - "@tanstack/solid-table": "^9.0.0-beta.12", + "@tanstack/solid-table": "^9.0.0-beta.15", "solid-js": "^1.9.13" } } diff --git a/examples/solid/column-resizing-performant/package.json b/examples/solid/column-resizing-performant/package.json index f76cd8377e..63b97eb2a1 100644 --- a/examples/solid/column-resizing-performant/package.json +++ b/examples/solid/column-resizing-performant/package.json @@ -16,7 +16,7 @@ "vite-plugin-solid": "^2.11.12" }, "dependencies": { - "@tanstack/solid-table": "^9.0.0-beta.12", + "@tanstack/solid-table": "^9.0.0-beta.15", "solid-js": "^1.9.13" } } diff --git a/examples/solid/column-resizing/package.json b/examples/solid/column-resizing/package.json index 232da4fde7..ba4efd4ff2 100644 --- a/examples/solid/column-resizing/package.json +++ b/examples/solid/column-resizing/package.json @@ -16,7 +16,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/solid-table": "^9.0.0-beta.12", + "@tanstack/solid-table": "^9.0.0-beta.15", "solid-js": "^1.9.13" } } diff --git a/examples/solid/column-sizing/package.json b/examples/solid/column-sizing/package.json index 7059b4d115..d225318aeb 100644 --- a/examples/solid/column-sizing/package.json +++ b/examples/solid/column-sizing/package.json @@ -16,7 +16,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/solid-table": "^9.0.0-beta.12", + "@tanstack/solid-table": "^9.0.0-beta.15", "solid-js": "^1.9.13" } } diff --git a/examples/solid/column-visibility/package.json b/examples/solid/column-visibility/package.json index 1427c7eb05..a69c9137ea 100644 --- a/examples/solid/column-visibility/package.json +++ b/examples/solid/column-visibility/package.json @@ -16,7 +16,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/solid-table": "^9.0.0-beta.12", + "@tanstack/solid-table": "^9.0.0-beta.15", "solid-js": "^1.9.13" } } diff --git a/examples/solid/composable-tables/package.json b/examples/solid/composable-tables/package.json index 6b62b75363..32c2e5c59c 100644 --- a/examples/solid/composable-tables/package.json +++ b/examples/solid/composable-tables/package.json @@ -16,8 +16,8 @@ }, "dependencies": { "@tanstack/solid-devtools": "^0.8.5", - "@tanstack/solid-table": "^9.0.0-beta.12", - "@tanstack/solid-table-devtools": "^9.0.0-beta.12", + "@tanstack/solid-table": "^9.0.0-beta.15", + "@tanstack/solid-table-devtools": "^9.0.0-beta.15", "solid-js": "^1.9.13" } } diff --git a/examples/solid/composable-tables/src/App.tsx b/examples/solid/composable-tables/src/App.tsx index c7c83e0d03..3a84f00366 100644 --- a/examples/solid/composable-tables/src/App.tsx +++ b/examples/solid/composable-tables/src/App.tsx @@ -1,6 +1,7 @@ import { For, createSignal } from 'solid-js' import { useTanStackTableDevtools } from '@tanstack/solid-table-devtools' import { createAppColumnHelper, createAppTable } from './hooks/table' +import { IndeterminateCheckbox } from './components/indeterminate-checkbox' import { makeData, makeProductData } from './makeData' import type { Person, Product } from './makeData' // Import cell components directly - they use useCellContext internally @@ -26,6 +27,19 @@ function UsersTable() { const columns = // NOTE: You must use `createAppColumnHelper` instead of `createColumnHelper` when using pre-bound components like personColumnHelper.columns([ + personColumnHelper.display({ + id: 'select', + header: ({ table }) => ( + // Solid tracks these calls natively, so no Subscribe is needed. + + ), + // Cell uses the pre-bound SelectCell component via AppCell + cell: ({ cell }) => , + }), personColumnHelper.accessor('firstName', { header: 'First Name', footer: (props) => props.column.id, @@ -71,6 +85,7 @@ function UsersTable() { return data() }, debugTable: true, + enableRowSelection: true, // more table options }) @@ -99,124 +114,128 @@ function UsersTable() { /> {/* Table element */} - - - - {(headerGroup) => ( - - - {(h) => ( - - {(header) => ( - - )} - - )} - - - )} - - - - - {(row) => ( - - - {(c) => ( - - {(cell) => ( - - )} - - )} - - - )} - - - - - {(footerGroup) => ( - - - {(f) => ( - - {(footer) => { - const columnId = footer.column.id - const hasFilter = () => - columnFilters().some((cf) => cf.id === columnId) - - return ( - + )} + + + + + {(footerGroup) => ( + + + {(f) => ( + + {(footer) => { + const columnId = footer.column.id + const hasFilter = () => + columnFilters().some( + (cf) => cf.id === columnId, + ) + + return ( + + ) + }} + + )} + + + )} + + +
- {header.isPlaceholder ? null : ( - <> - - - - {/* Show sort order number when multiple columns sorted */} - {sorting().length > 1 && - sorting().findIndex( - (s) => s.id === header.column.id, - ) > -1 && ( - - {sorting().findIndex( - (s) => s.id === header.column.id, - ) + 1} - - )} - - )} -
- {/* Cell components are pre-bound via AppCell */} - -
- {footer.isPlaceholder ? null : ( +
+ + + + {(headerGroup) => ( + + + {(h) => ( + + {(header) => ( + + )} + + )} + + + )} + + + + + {(row) => ( + + + {(c) => ( + + {(cell) => ( + - ) - }} - - )} - - - )} - - -
+ {header.isPlaceholder ? null : ( <> - {/* Use FooterSum for numeric columns, FooterColumnId for others */} - {columnId === 'age' || - columnId === 'visits' || - columnId === 'progress' ? ( - <> - - {hasFilter() && ( - - {' '} - (filtered) - - )} - - ) : columnId === 'actions' ? null : ( - <> - - {hasFilter() && ( - - {' '} - ✓ - - )} - - )} + + + + {/* Show sort order number when multiple columns sorted */} + {sorting().length > 1 && + sorting().findIndex( + (s) => s.id === header.column.id, + ) > -1 && ( + + {sorting().findIndex( + (s) => s.id === header.column.id, + ) + 1} + + )} )} +
+ {/* Cell components are pre-bound via AppCell */} +
+ )} + + )} + +
+ {footer.isPlaceholder ? null : ( + <> + {/* Use FooterSum for numeric columns, FooterColumnId for others */} + {columnId === 'age' || + columnId === 'visits' || + columnId === 'progress' ? ( + <> + + {hasFilter() && ( + + {' '} + (filtered) + + )} + + ) : columnId === 'actions' ? null : ( + <> + + {hasFilter() && ( + + {' '} + ✓ + + )} + + )} + + )} +
+ {/* Pagination using pre-bound component */} @@ -245,6 +264,19 @@ function ProductsTable() { // Define columns using the column helper - different structure than Users table const columns = productColumnHelper.columns([ + productColumnHelper.display({ + id: 'select', + header: ({ table }) => ( + // Solid tracks these calls natively, so no Subscribe is needed. + + ), + // Cell uses the pre-bound SelectCell component via AppCell + cell: ({ cell }) => , + }), productColumnHelper.accessor('name', { header: 'Product Name', footer: (props) => props.column.id, @@ -281,6 +313,7 @@ function ProductsTable() { return data() }, getRowId: (row) => row.id, + enableRowSelection: true, }) useTanStackTableDevtools(table) @@ -306,123 +339,127 @@ function ProductsTable() { /> {/* Table element */} - - - - {(headerGroup) => ( - - - {(h) => ( - - {(header) => ( - - )} - - )} - - - )} - - - - - {(row) => ( - - - {(c) => ( - - {(cell) => ( - - )} - - )} - - - )} - - - - - {(footerGroup) => ( - - - {(f) => ( - - {(footer) => { - const columnId = footer.column.id - const hasFilter = () => - columnFilters().some((cf) => cf.id === columnId) - - return ( - + )} + + + + + {(footerGroup) => ( + + + {(f) => ( + + {(footer) => { + const columnId = footer.column.id + const hasFilter = () => + columnFilters().some( + (cf) => cf.id === columnId, + ) + + return ( + + ) + }} + + )} + + + )} + + +
- {header.isPlaceholder ? null : ( - <> - - - - {sorting().length > 1 && - sorting().findIndex( - (s) => s.id === header.column.id, - ) > -1 && ( - - {sorting().findIndex( - (s) => s.id === header.column.id, - ) + 1} - - )} - - )} -
- {/* Cell components are pre-bound via AppCell */} - -
- {footer.isPlaceholder ? null : ( +
+ + + + {(headerGroup) => ( + + + {(h) => ( + + {(header) => ( + + )} + + )} + + + )} + + + + + {(row) => ( + + + {(c) => ( + + {(cell) => ( + - ) - }} - - )} - - - )} - - -
+ {header.isPlaceholder ? null : ( <> - {/* Use FooterSum for numeric columns, FooterColumnId for others */} - {columnId === 'price' || - columnId === 'stock' || - columnId === 'rating' ? ( - <> - - {hasFilter() && ( - - {' '} - (filtered) - - )} - - ) : ( - <> - - {hasFilter() && ( - - {' '} - ✓ - - )} - - )} + + + + {sorting().length > 1 && + sorting().findIndex( + (s) => s.id === header.column.id, + ) > -1 && ( + + {sorting().findIndex( + (s) => s.id === header.column.id, + ) + 1} + + )} )} +
+ {/* Cell components are pre-bound via AppCell */} +
+ )} + + )} + +
+ {footer.isPlaceholder ? null : ( + <> + {/* Use FooterSum for numeric columns, FooterColumnId for others */} + {columnId === 'price' || + columnId === 'stock' || + columnId === 'rating' ? ( + <> + + {hasFilter() && ( + + {' '} + (filtered) + + )} + + ) : ( + <> + + {hasFilter() && ( + + {' '} + ✓ + + )} + + )} + + )} +
+ {/* Pagination using the same pre-bound component */} diff --git a/examples/solid/composable-tables/src/components/cell-components.tsx b/examples/solid/composable-tables/src/components/cell-components.tsx index af78520679..1cb6b35c20 100644 --- a/examples/solid/composable-tables/src/components/cell-components.tsx +++ b/examples/solid/composable-tables/src/components/cell-components.tsx @@ -5,6 +5,27 @@ * in AppCell children, e.g., */ import { useCellContext } from '../hooks/table' +import { IndeterminateCheckbox } from './indeterminate-checkbox' + +/** + * Row-selection checkbox cell - toggles selection for the current row. + * + * Solid tracks the `row.getIsSelected()` etc. calls natively, so passing them + * as accessors keeps the checkbox reactive without any Subscribe boundary. + */ +export function SelectCell() { + const cell = useCellContext() + const row = cell.row + + return ( + + ) +} /** * Generic text cell renderer diff --git a/examples/solid/composable-tables/src/components/indeterminate-checkbox.tsx b/examples/solid/composable-tables/src/components/indeterminate-checkbox.tsx new file mode 100644 index 0000000000..ed760d1f7d --- /dev/null +++ b/examples/solid/composable-tables/src/components/indeterminate-checkbox.tsx @@ -0,0 +1,36 @@ +/** + * Indeterminate checkbox used by the row-selection column + * (both the select-all header and the per-row select cell). + * + * Solid handles reactivity natively, so `checked`/`indeterminate` are read + * from props (kept reactive by the callers) and the indeterminate DOM property + * is synced via a ref in createEffect. + */ +import { createEffect } from 'solid-js' + +export function IndeterminateCheckbox(props: { + indeterminate?: boolean + class?: string + checked?: boolean + disabled?: boolean + onChange?: (event: Event) => void +}) { + let ref: HTMLInputElement | undefined + + createEffect(() => { + if (typeof props.indeterminate === 'boolean' && ref) { + ref.indeterminate = !props.checked && props.indeterminate + } + }) + + return ( + + ) +} diff --git a/examples/solid/composable-tables/src/hooks/table.ts b/examples/solid/composable-tables/src/hooks/table.ts index d8379b071c..377aed21e8 100644 --- a/examples/solid/composable-tables/src/hooks/table.ts +++ b/examples/solid/composable-tables/src/hooks/table.ts @@ -13,6 +13,7 @@ import { createTableHook, filterFns, rowPaginationFeature, + rowSelectionFeature, rowSortingFeature, sortFns, tableFeatures, @@ -32,6 +33,7 @@ import { PriceCell, ProgressCell, RowActionsCell, + SelectCell, StatusCell, TextCell, } from '../components/cell-components' @@ -64,6 +66,7 @@ export const { features: tableFeatures({ columnFilteringFeature, rowPaginationFeature, + rowSelectionFeature, rowSortingFeature, sortedRowModel: createSortedRowModel(), filteredRowModel: createFilteredRowModel(), @@ -84,6 +87,7 @@ export const { // Register cell-level components (accessible via cell.ComponentName in AppCell) cellComponents: { + SelectCell, TextCell, NumberCell, StatusCell, diff --git a/examples/solid/composable-tables/src/index.css b/examples/solid/composable-tables/src/index.css index 4d8fef0142..8dd0d1ca90 100644 --- a/examples/solid/composable-tables/src/index.css +++ b/examples/solid/composable-tables/src/index.css @@ -603,3 +603,17 @@ tfoot th { font-size: 1.875rem; font-weight: 700; } + +/* Fixed-height scroll container for the table body. When the page size exceeds + ~12 rows the body overflows and scrolls, with sticky headers. */ +.table-scroll { + max-height: 400px; + overflow: auto; + border: 1px solid lightgray; +} + +.table-scroll thead th { + position: sticky; + top: 0; + z-index: 1; +} diff --git a/examples/solid/expanding/package.json b/examples/solid/expanding/package.json index 00bb19bf02..8cb37588e2 100644 --- a/examples/solid/expanding/package.json +++ b/examples/solid/expanding/package.json @@ -16,7 +16,7 @@ "vite-plugin-solid": "^2.11.12" }, "dependencies": { - "@tanstack/solid-table": "^9.0.0-beta.12", + "@tanstack/solid-table": "^9.0.0-beta.15", "solid-js": "^1.9.13" } } diff --git a/examples/solid/filters-faceted/package.json b/examples/solid/filters-faceted/package.json index 0eb02431e7..cd48932bcb 100644 --- a/examples/solid/filters-faceted/package.json +++ b/examples/solid/filters-faceted/package.json @@ -17,7 +17,7 @@ }, "dependencies": { "@tanstack/solid-pacer": "^0.21.1", - "@tanstack/solid-table": "^9.0.0-beta.12", + "@tanstack/solid-table": "^9.0.0-beta.15", "solid-js": "^1.9.13" } } diff --git a/examples/solid/filters-fuzzy/package.json b/examples/solid/filters-fuzzy/package.json index b2a58f1138..c44c7b6b7b 100644 --- a/examples/solid/filters-fuzzy/package.json +++ b/examples/solid/filters-fuzzy/package.json @@ -18,7 +18,7 @@ "dependencies": { "@tanstack/match-sorter-utils": "^9.0.0-beta.0", "@tanstack/solid-pacer": "^0.21.1", - "@tanstack/solid-table": "^9.0.0-beta.12", + "@tanstack/solid-table": "^9.0.0-beta.15", "solid-js": "^1.9.13" } } diff --git a/examples/solid/filters/package.json b/examples/solid/filters/package.json index 6865fade35..dd271280aa 100644 --- a/examples/solid/filters/package.json +++ b/examples/solid/filters/package.json @@ -17,7 +17,7 @@ }, "dependencies": { "@tanstack/solid-pacer": "^0.21.1", - "@tanstack/solid-table": "^9.0.0-beta.12", + "@tanstack/solid-table": "^9.0.0-beta.15", "solid-js": "^1.9.13" } } diff --git a/examples/solid/grouping/package.json b/examples/solid/grouping/package.json index 94d6e5c698..1fb8920d9a 100644 --- a/examples/solid/grouping/package.json +++ b/examples/solid/grouping/package.json @@ -16,7 +16,7 @@ "vite-plugin-solid": "^2.11.12" }, "dependencies": { - "@tanstack/solid-table": "^9.0.0-beta.12", + "@tanstack/solid-table": "^9.0.0-beta.15", "solid-js": "^1.9.13" } } diff --git a/examples/solid/kitchen-sink/package.json b/examples/solid/kitchen-sink/package.json index e1c59b9a69..b8e2acf6f5 100644 --- a/examples/solid/kitchen-sink/package.json +++ b/examples/solid/kitchen-sink/package.json @@ -18,8 +18,8 @@ "dependencies": { "@tanstack/match-sorter-utils": "^9.0.0-beta.0", "@tanstack/solid-devtools": "^0.8.5", - "@tanstack/solid-table": "^9.0.0-beta.12", - "@tanstack/solid-table-devtools": "^9.0.0-beta.12", + "@tanstack/solid-table": "^9.0.0-beta.15", + "@tanstack/solid-table-devtools": "^9.0.0-beta.15", "solid-js": "^1.9.13" } } diff --git a/examples/solid/pagination/package.json b/examples/solid/pagination/package.json index 4fe0782265..d91c97eee4 100644 --- a/examples/solid/pagination/package.json +++ b/examples/solid/pagination/package.json @@ -16,7 +16,7 @@ "vite-plugin-solid": "^2.11.12" }, "dependencies": { - "@tanstack/solid-table": "^9.0.0-beta.12", + "@tanstack/solid-table": "^9.0.0-beta.15", "solid-js": "^1.9.13" } } diff --git a/examples/solid/row-pinning/package.json b/examples/solid/row-pinning/package.json index 05a1822e7b..de16d9bb5f 100644 --- a/examples/solid/row-pinning/package.json +++ b/examples/solid/row-pinning/package.json @@ -16,7 +16,7 @@ "vite-plugin-solid": "^2.11.12" }, "dependencies": { - "@tanstack/solid-table": "^9.0.0-beta.12", + "@tanstack/solid-table": "^9.0.0-beta.15", "solid-js": "^1.9.13" } } diff --git a/examples/solid/row-selection/package.json b/examples/solid/row-selection/package.json index ec961d980c..8db403ebbf 100644 --- a/examples/solid/row-selection/package.json +++ b/examples/solid/row-selection/package.json @@ -17,8 +17,8 @@ }, "dependencies": { "@tanstack/solid-devtools": "^0.8.5", - "@tanstack/solid-table": "^9.0.0-beta.12", - "@tanstack/solid-table-devtools": "^9.0.0-beta.12", + "@tanstack/solid-table": "^9.0.0-beta.15", + "@tanstack/solid-table-devtools": "^9.0.0-beta.15", "solid-js": "^1.9.13" } } diff --git a/examples/solid/sorting/package.json b/examples/solid/sorting/package.json index 688453a364..fff48a81e8 100644 --- a/examples/solid/sorting/package.json +++ b/examples/solid/sorting/package.json @@ -16,7 +16,7 @@ "vite-plugin-solid": "^2.11.12" }, "dependencies": { - "@tanstack/solid-table": "^9.0.0-beta.12", + "@tanstack/solid-table": "^9.0.0-beta.15", "solid-js": "^1.9.13" } } diff --git a/examples/solid/sub-components/package.json b/examples/solid/sub-components/package.json index de36b0c190..e8f353d6d9 100644 --- a/examples/solid/sub-components/package.json +++ b/examples/solid/sub-components/package.json @@ -16,7 +16,7 @@ "vite-plugin-solid": "^2.11.12" }, "dependencies": { - "@tanstack/solid-table": "^9.0.0-beta.12", + "@tanstack/solid-table": "^9.0.0-beta.15", "solid-js": "^1.9.13" } } diff --git a/examples/solid/virtualized-columns/package.json b/examples/solid/virtualized-columns/package.json index 8bdb48900f..91426de888 100644 --- a/examples/solid/virtualized-columns/package.json +++ b/examples/solid/virtualized-columns/package.json @@ -16,7 +16,7 @@ "vite-plugin-solid": "^2.11.12" }, "dependencies": { - "@tanstack/solid-table": "^9.0.0-beta.12", + "@tanstack/solid-table": "^9.0.0-beta.15", "@tanstack/solid-virtual": "^3.13.28", "solid-js": "^1.9.13" } diff --git a/examples/solid/virtualized-infinite-scrolling/package.json b/examples/solid/virtualized-infinite-scrolling/package.json index e7213d4f21..99ee5d7487 100644 --- a/examples/solid/virtualized-infinite-scrolling/package.json +++ b/examples/solid/virtualized-infinite-scrolling/package.json @@ -18,7 +18,7 @@ "dependencies": { "@tanstack/solid-query": "^5.101.0", "@tanstack/solid-store": "^0.11.0", - "@tanstack/solid-table": "^9.0.0-beta.12", + "@tanstack/solid-table": "^9.0.0-beta.15", "@tanstack/solid-virtual": "^3.13.28", "solid-js": "^1.9.13" } diff --git a/examples/solid/virtualized-rows/package.json b/examples/solid/virtualized-rows/package.json index cfbb5492b4..603a1d749e 100644 --- a/examples/solid/virtualized-rows/package.json +++ b/examples/solid/virtualized-rows/package.json @@ -16,7 +16,7 @@ "vite-plugin-solid": "^2.11.12" }, "dependencies": { - "@tanstack/solid-table": "^9.0.0-beta.12", + "@tanstack/solid-table": "^9.0.0-beta.15", "@tanstack/solid-virtual": "^3.13.28", "solid-js": "^1.9.13" } diff --git a/examples/solid/with-tanstack-form/package.json b/examples/solid/with-tanstack-form/package.json index c57a70a006..60483f501d 100644 --- a/examples/solid/with-tanstack-form/package.json +++ b/examples/solid/with-tanstack-form/package.json @@ -17,7 +17,7 @@ }, "dependencies": { "@tanstack/solid-form": "^1.33.0", - "@tanstack/solid-table": "^9.0.0-beta.12", + "@tanstack/solid-table": "^9.0.0-beta.15", "solid-js": "^1.9.13", "zod": "^4.4.3" } diff --git a/examples/solid/with-tanstack-query/package.json b/examples/solid/with-tanstack-query/package.json index 0da3459162..7461ba3022 100644 --- a/examples/solid/with-tanstack-query/package.json +++ b/examples/solid/with-tanstack-query/package.json @@ -18,7 +18,7 @@ "dependencies": { "@tanstack/solid-query": "^5.101.0", "@tanstack/solid-store": "^0.11.0", - "@tanstack/solid-table": "^9.0.0-beta.12", + "@tanstack/solid-table": "^9.0.0-beta.15", "solid-js": "^1.9.13" } } diff --git a/examples/solid/with-tanstack-router/package.json b/examples/solid/with-tanstack-router/package.json index 586aa5c6ab..4f38617cc6 100644 --- a/examples/solid/with-tanstack-router/package.json +++ b/examples/solid/with-tanstack-router/package.json @@ -20,7 +20,7 @@ "@tanstack/solid-pacer": "^0.21.1", "@tanstack/solid-query": "^5.101.0", "@tanstack/solid-router": "^1.170.15", - "@tanstack/solid-table": "^9.0.0-beta.12", + "@tanstack/solid-table": "^9.0.0-beta.15", "solid-js": "^1.9.13" } } diff --git a/examples/svelte/basic-app-table/package.json b/examples/svelte/basic-app-table/package.json index a1bdfea428..dcec6d38a0 100644 --- a/examples/svelte/basic-app-table/package.json +++ b/examples/svelte/basic-app-table/package.json @@ -13,7 +13,7 @@ "@faker-js/faker": "^10.4.0", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tanstack/svelte-table": "^9.0.0-beta.12", + "@tanstack/svelte-table": "^9.0.0-beta.15", "@tsconfig/svelte": "^5.0.8", "svelte": "^5.56.2", "svelte-check": "^4.6.0", diff --git a/examples/svelte/basic-create-table/package.json b/examples/svelte/basic-create-table/package.json index 3c58cd25ff..de6d56441a 100644 --- a/examples/svelte/basic-create-table/package.json +++ b/examples/svelte/basic-create-table/package.json @@ -13,7 +13,7 @@ "@faker-js/faker": "^10.4.0", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tanstack/svelte-table": "^9.0.0-beta.12", + "@tanstack/svelte-table": "^9.0.0-beta.15", "@tsconfig/svelte": "^5.0.8", "svelte": "^5.56.2", "svelte-check": "^4.6.0", diff --git a/examples/svelte/basic-external-atoms/package.json b/examples/svelte/basic-external-atoms/package.json index 4120cf6d2b..5787868205 100644 --- a/examples/svelte/basic-external-atoms/package.json +++ b/examples/svelte/basic-external-atoms/package.json @@ -16,7 +16,7 @@ "@faker-js/faker": "^10.4.0", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tanstack/svelte-table": "^9.0.0-beta.12", + "@tanstack/svelte-table": "^9.0.0-beta.15", "@tsconfig/svelte": "^5.0.8", "svelte": "^5.56.2", "svelte-check": "^4.6.0", diff --git a/examples/svelte/basic-external-state/package.json b/examples/svelte/basic-external-state/package.json index 95e7cf3db7..0324a1056c 100644 --- a/examples/svelte/basic-external-state/package.json +++ b/examples/svelte/basic-external-state/package.json @@ -13,7 +13,7 @@ "@faker-js/faker": "^10.4.0", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tanstack/svelte-table": "^9.0.0-beta.12", + "@tanstack/svelte-table": "^9.0.0-beta.15", "@tsconfig/svelte": "^5.0.8", "svelte": "^5.56.2", "svelte-check": "^4.6.0", diff --git a/examples/svelte/basic-snippets/package.json b/examples/svelte/basic-snippets/package.json index eccab7a6d1..ea80d2138b 100644 --- a/examples/svelte/basic-snippets/package.json +++ b/examples/svelte/basic-snippets/package.json @@ -13,7 +13,7 @@ "@faker-js/faker": "^10.4.0", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tanstack/svelte-table": "^9.0.0-beta.12", + "@tanstack/svelte-table": "^9.0.0-beta.15", "@tsconfig/svelte": "^5.0.8", "svelte": "^5.56.2", "svelte-check": "^4.6.0", diff --git a/examples/svelte/column-groups/package.json b/examples/svelte/column-groups/package.json index 15b58f2f07..12bf051bb9 100644 --- a/examples/svelte/column-groups/package.json +++ b/examples/svelte/column-groups/package.json @@ -13,7 +13,7 @@ "@faker-js/faker": "^10.4.0", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tanstack/svelte-table": "^9.0.0-beta.12", + "@tanstack/svelte-table": "^9.0.0-beta.15", "@tsconfig/svelte": "^5.0.8", "svelte": "^5.56.2", "svelte-check": "^4.6.0", diff --git a/examples/svelte/column-ordering/package.json b/examples/svelte/column-ordering/package.json index aaa4673798..9748a73134 100644 --- a/examples/svelte/column-ordering/package.json +++ b/examples/svelte/column-ordering/package.json @@ -13,7 +13,7 @@ "@faker-js/faker": "^10.4.0", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tanstack/svelte-table": "^9.0.0-beta.12", + "@tanstack/svelte-table": "^9.0.0-beta.15", "@tsconfig/svelte": "^5.0.8", "svelte": "^5.56.2", "svelte-check": "^4.6.0", diff --git a/examples/svelte/column-pinning-split/package.json b/examples/svelte/column-pinning-split/package.json index d9503d652a..fbe919275b 100644 --- a/examples/svelte/column-pinning-split/package.json +++ b/examples/svelte/column-pinning-split/package.json @@ -13,7 +13,7 @@ "@faker-js/faker": "^10.4.0", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tanstack/svelte-table": "^9.0.0-beta.12", + "@tanstack/svelte-table": "^9.0.0-beta.15", "@tsconfig/svelte": "^5.0.8", "svelte": "^5.56.2", "svelte-check": "^4.6.0", diff --git a/examples/svelte/column-pinning-sticky/package.json b/examples/svelte/column-pinning-sticky/package.json index 885e874220..97bf265882 100644 --- a/examples/svelte/column-pinning-sticky/package.json +++ b/examples/svelte/column-pinning-sticky/package.json @@ -13,7 +13,7 @@ "@faker-js/faker": "^10.4.0", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tanstack/svelte-table": "^9.0.0-beta.12", + "@tanstack/svelte-table": "^9.0.0-beta.15", "@tsconfig/svelte": "^5.0.8", "svelte": "^5.56.2", "svelte-check": "^4.6.0", diff --git a/examples/svelte/column-pinning/package.json b/examples/svelte/column-pinning/package.json index bcc896a7df..802e3c6757 100644 --- a/examples/svelte/column-pinning/package.json +++ b/examples/svelte/column-pinning/package.json @@ -13,7 +13,7 @@ "@faker-js/faker": "^10.4.0", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tanstack/svelte-table": "^9.0.0-beta.12", + "@tanstack/svelte-table": "^9.0.0-beta.15", "@tsconfig/svelte": "^5.0.8", "svelte": "^5.56.2", "svelte-check": "^4.6.0", diff --git a/examples/svelte/column-resizing-performant/package.json b/examples/svelte/column-resizing-performant/package.json index ee711ac1b4..eaaa204dc7 100644 --- a/examples/svelte/column-resizing-performant/package.json +++ b/examples/svelte/column-resizing-performant/package.json @@ -13,7 +13,7 @@ "@faker-js/faker": "^10.4.0", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tanstack/svelte-table": "^9.0.0-beta.12", + "@tanstack/svelte-table": "^9.0.0-beta.15", "@tsconfig/svelte": "^5.0.8", "svelte": "^5.56.2", "svelte-check": "^4.6.0", diff --git a/examples/svelte/column-resizing/package.json b/examples/svelte/column-resizing/package.json index 490940303b..2cf4d4023e 100644 --- a/examples/svelte/column-resizing/package.json +++ b/examples/svelte/column-resizing/package.json @@ -13,7 +13,7 @@ "@faker-js/faker": "^10.4.0", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tanstack/svelte-table": "^9.0.0-beta.12", + "@tanstack/svelte-table": "^9.0.0-beta.15", "@tsconfig/svelte": "^5.0.8", "svelte": "^5.56.2", "svelte-check": "^4.6.0", diff --git a/examples/svelte/column-sizing/package.json b/examples/svelte/column-sizing/package.json index f4183ae6ac..cb2b307b4f 100644 --- a/examples/svelte/column-sizing/package.json +++ b/examples/svelte/column-sizing/package.json @@ -13,7 +13,7 @@ "@faker-js/faker": "^10.4.0", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tanstack/svelte-table": "^9.0.0-beta.12", + "@tanstack/svelte-table": "^9.0.0-beta.15", "@tsconfig/svelte": "^5.0.8", "svelte": "^5.56.2", "svelte-check": "^4.6.0", diff --git a/examples/svelte/column-visibility/package.json b/examples/svelte/column-visibility/package.json index 36c241174e..cd95f7f2cf 100644 --- a/examples/svelte/column-visibility/package.json +++ b/examples/svelte/column-visibility/package.json @@ -13,7 +13,7 @@ "@faker-js/faker": "^10.4.0", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tanstack/svelte-table": "^9.0.0-beta.12", + "@tanstack/svelte-table": "^9.0.0-beta.15", "@tsconfig/svelte": "^5.0.8", "svelte": "^5.56.2", "svelte-check": "^4.6.0", diff --git a/examples/svelte/composable-tables/package.json b/examples/svelte/composable-tables/package.json index 41885ef043..836951b6c0 100644 --- a/examples/svelte/composable-tables/package.json +++ b/examples/svelte/composable-tables/package.json @@ -13,7 +13,7 @@ "@faker-js/faker": "^10.4.0", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tanstack/svelte-table": "^9.0.0-beta.12", + "@tanstack/svelte-table": "^9.0.0-beta.15", "@tsconfig/svelte": "^5.0.8", "svelte": "^5.56.2", "svelte-check": "^4.6.0", diff --git a/examples/svelte/composable-tables/src/components/ProductsTable.svelte b/examples/svelte/composable-tables/src/components/ProductsTable.svelte index 596db98a56..1aa036e8c6 100644 --- a/examples/svelte/composable-tables/src/components/ProductsTable.svelte +++ b/examples/svelte/composable-tables/src/components/ProductsTable.svelte @@ -24,6 +24,11 @@ // Define columns using the column helper - different structure than Users table const columns = productColumnHelper.columns([ + productColumnHelper.display({ + id: 'select', + header: ({ header }) => renderComponent(header.SelectHeader), + cell: ({ cell }) => renderComponent(cell.SelectCell), + }), productColumnHelper.accessor('name', { header: 'Product Name', footer: (props) => props.column.id, @@ -59,6 +64,7 @@ return data }, getRowId: (row) => row.id, + enableRowSelection: true, }) // Reactive derived values from table state @@ -84,6 +90,7 @@ /> +
{#each table.getHeaderGroups() as headerGroup (headerGroup.id) @@ -166,6 +173,7 @@ {/each}
+
diff --git a/examples/svelte/composable-tables/src/components/SelectCell.svelte b/examples/svelte/composable-tables/src/components/SelectCell.svelte new file mode 100644 index 0000000000..6b144f1a07 --- /dev/null +++ b/examples/svelte/composable-tables/src/components/SelectCell.svelte @@ -0,0 +1,31 @@ + + + + diff --git a/examples/svelte/composable-tables/src/components/SelectHeader.svelte b/examples/svelte/composable-tables/src/components/SelectHeader.svelte new file mode 100644 index 0000000000..c19be36e72 --- /dev/null +++ b/examples/svelte/composable-tables/src/components/SelectHeader.svelte @@ -0,0 +1,31 @@ + + + + + + e.stopPropagation()} +/> diff --git a/examples/svelte/composable-tables/src/components/UsersTable.svelte b/examples/svelte/composable-tables/src/components/UsersTable.svelte index a09cab1763..95fe06bc76 100644 --- a/examples/svelte/composable-tables/src/components/UsersTable.svelte +++ b/examples/svelte/composable-tables/src/components/UsersTable.svelte @@ -25,6 +25,11 @@ // NOTE: You must use `createAppColumnHelper` instead of `createColumnHelper` // when using pre-bound components like cell.TextCell const columns = personColumnHelper.columns([ + personColumnHelper.display({ + id: 'select', + header: ({ header }) => renderComponent(header.SelectHeader), + cell: ({ cell }) => renderComponent(cell.SelectCell), + }), personColumnHelper.accessor('firstName', { header: 'First Name', footer: (props) => props.column.id, @@ -68,6 +73,7 @@ get data() { return data }, + enableRowSelection: true, debugTable: true, }) @@ -96,6 +102,7 @@ /> +
{#each table.getHeaderGroups() as headerGroup (headerGroup.id) @@ -180,6 +187,7 @@ {/each}
+
diff --git a/examples/svelte/composable-tables/src/hooks/table.ts b/examples/svelte/composable-tables/src/hooks/table.ts index 9694a6b1cf..fcff4aca29 100644 --- a/examples/svelte/composable-tables/src/hooks/table.ts +++ b/examples/svelte/composable-tables/src/hooks/table.ts @@ -13,6 +13,7 @@ import { createTableHook, filterFns, rowPaginationFeature, + rowSelectionFeature, rowSortingFeature, sortFns, tableFeatures, @@ -29,6 +30,7 @@ import NumberCell from '../components/NumberCell.svelte' import PriceCell from '../components/PriceCell.svelte' import ProgressCell from '../components/ProgressCell.svelte' import RowActionsCell from '../components/RowActionsCell.svelte' +import SelectCell from '../components/SelectCell.svelte' import StatusCell from '../components/StatusCell.svelte' import TextCell from '../components/TextCell.svelte' @@ -36,6 +38,7 @@ import TextCell from '../components/TextCell.svelte' import ColumnFilter from '../components/ColumnFilter.svelte' import FooterColumnId from '../components/FooterColumnId.svelte' import FooterSum from '../components/FooterSum.svelte' +import SelectHeader from '../components/SelectHeader.svelte' import SortIndicator from '../components/SortIndicator.svelte' /** @@ -58,6 +61,7 @@ export const { features: tableFeatures({ columnFilteringFeature, rowPaginationFeature, + rowSelectionFeature, rowSortingFeature, sortedRowModel: createSortedRowModel(), filteredRowModel: createFilteredRowModel(), @@ -78,6 +82,7 @@ export const { // Register cell-level components (accessible via cell.ComponentName in AppCell) cellComponents: { + SelectCell, TextCell, NumberCell, StatusCell, @@ -89,6 +94,7 @@ export const { // Register header/footer-level components (accessible via header.ComponentName in AppHeader/AppFooter) headerComponents: { + SelectHeader, SortIndicator, ColumnFilter, FooterColumnId, diff --git a/examples/svelte/composable-tables/src/index.css b/examples/svelte/composable-tables/src/index.css index 4d8fef0142..09ce02888c 100644 --- a/examples/svelte/composable-tables/src/index.css +++ b/examples/svelte/composable-tables/src/index.css @@ -43,6 +43,18 @@ tfoot th { border-spacing: 0; } +.table-scroll { + max-height: 400px; + overflow: auto; + border: 1px solid lightgray; +} + +.table-scroll thead th { + position: sticky; + top: 0; + z-index: 1; +} + .pagination { display: flex; align-items: center; diff --git a/examples/svelte/expanding/package.json b/examples/svelte/expanding/package.json index 736c5a6c43..a152abbe3b 100644 --- a/examples/svelte/expanding/package.json +++ b/examples/svelte/expanding/package.json @@ -13,7 +13,7 @@ "@faker-js/faker": "^10.4.0", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tanstack/svelte-table": "^9.0.0-beta.12", + "@tanstack/svelte-table": "^9.0.0-beta.15", "@tsconfig/svelte": "^5.0.8", "svelte": "^5.56.2", "svelte-check": "^4.6.0", diff --git a/examples/svelte/filtering/package.json b/examples/svelte/filtering/package.json index cc52ff0ab8..19d6bdb039 100644 --- a/examples/svelte/filtering/package.json +++ b/examples/svelte/filtering/package.json @@ -13,7 +13,7 @@ "@faker-js/faker": "^10.4.0", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tanstack/svelte-table": "^9.0.0-beta.12", + "@tanstack/svelte-table": "^9.0.0-beta.15", "@tsconfig/svelte": "^5.0.8", "svelte": "^5.56.2", "svelte-check": "^4.6.0", diff --git a/examples/svelte/filters-faceted/package.json b/examples/svelte/filters-faceted/package.json index 04a1c61a2a..965e80316d 100644 --- a/examples/svelte/filters-faceted/package.json +++ b/examples/svelte/filters-faceted/package.json @@ -13,7 +13,7 @@ "@faker-js/faker": "^10.4.0", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tanstack/svelte-table": "^9.0.0-beta.12", + "@tanstack/svelte-table": "^9.0.0-beta.15", "@tsconfig/svelte": "^5.0.8", "svelte": "^5.56.2", "svelte-check": "^4.6.0", diff --git a/examples/svelte/filters-fuzzy/package.json b/examples/svelte/filters-fuzzy/package.json index 21827c3bb1..ba8c3ad512 100644 --- a/examples/svelte/filters-fuzzy/package.json +++ b/examples/svelte/filters-fuzzy/package.json @@ -14,7 +14,7 @@ "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.1.2", "@tanstack/match-sorter-utils": "^9.0.0-beta.0", - "@tanstack/svelte-table": "^9.0.0-beta.12", + "@tanstack/svelte-table": "^9.0.0-beta.15", "@tsconfig/svelte": "^5.0.8", "svelte": "^5.56.2", "svelte-check": "^4.6.0", diff --git a/examples/svelte/grouping/package.json b/examples/svelte/grouping/package.json index 1aee4727e9..036e01d3c3 100644 --- a/examples/svelte/grouping/package.json +++ b/examples/svelte/grouping/package.json @@ -13,7 +13,7 @@ "@faker-js/faker": "^10.4.0", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tanstack/svelte-table": "^9.0.0-beta.12", + "@tanstack/svelte-table": "^9.0.0-beta.15", "@tsconfig/svelte": "^5.0.8", "svelte": "^5.56.2", "svelte-check": "^4.6.0", diff --git a/examples/svelte/kitchen-sink/package.json b/examples/svelte/kitchen-sink/package.json index da3d9f4fe3..ed2fa0566f 100644 --- a/examples/svelte/kitchen-sink/package.json +++ b/examples/svelte/kitchen-sink/package.json @@ -14,7 +14,7 @@ "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.1.2", "@tanstack/match-sorter-utils": "^9.0.0-beta.0", - "@tanstack/svelte-table": "^9.0.0-beta.12", + "@tanstack/svelte-table": "^9.0.0-beta.15", "@tsconfig/svelte": "^5.0.8", "svelte": "^5.56.2", "svelte-check": "^4.6.0", diff --git a/examples/svelte/pagination/package.json b/examples/svelte/pagination/package.json index 35adaddacd..769166ad23 100644 --- a/examples/svelte/pagination/package.json +++ b/examples/svelte/pagination/package.json @@ -13,7 +13,7 @@ "@faker-js/faker": "^10.4.0", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tanstack/svelte-table": "^9.0.0-beta.12", + "@tanstack/svelte-table": "^9.0.0-beta.15", "@tsconfig/svelte": "^5.0.8", "svelte": "^5.56.2", "svelte-check": "^4.6.0", diff --git a/examples/svelte/row-pinning/package.json b/examples/svelte/row-pinning/package.json index 920556b7d9..67bb633273 100644 --- a/examples/svelte/row-pinning/package.json +++ b/examples/svelte/row-pinning/package.json @@ -13,7 +13,7 @@ "@faker-js/faker": "^10.4.0", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tanstack/svelte-table": "^9.0.0-beta.12", + "@tanstack/svelte-table": "^9.0.0-beta.15", "@tsconfig/svelte": "^5.0.8", "svelte": "^5.56.2", "svelte-check": "^4.6.0", diff --git a/examples/svelte/row-selection/package.json b/examples/svelte/row-selection/package.json index c75ec4e695..f1686c9e0c 100644 --- a/examples/svelte/row-selection/package.json +++ b/examples/svelte/row-selection/package.json @@ -13,7 +13,7 @@ "@faker-js/faker": "^10.4.0", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tanstack/svelte-table": "^9.0.0-beta.12", + "@tanstack/svelte-table": "^9.0.0-beta.15", "@tsconfig/svelte": "^5.0.8", "svelte": "^5.56.2", "svelte-check": "^4.6.0", diff --git a/examples/svelte/sorting/package.json b/examples/svelte/sorting/package.json index 853ef444ef..cb1a6a3567 100644 --- a/examples/svelte/sorting/package.json +++ b/examples/svelte/sorting/package.json @@ -13,7 +13,7 @@ "@faker-js/faker": "^10.4.0", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tanstack/svelte-table": "^9.0.0-beta.12", + "@tanstack/svelte-table": "^9.0.0-beta.15", "@tsconfig/svelte": "^5.0.8", "svelte": "^5.56.2", "svelte-check": "^4.6.0", diff --git a/examples/svelte/sub-components/package.json b/examples/svelte/sub-components/package.json index 4b621c3b98..2dabbfbd99 100644 --- a/examples/svelte/sub-components/package.json +++ b/examples/svelte/sub-components/package.json @@ -13,7 +13,7 @@ "@faker-js/faker": "^10.4.0", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tanstack/svelte-table": "^9.0.0-beta.12", + "@tanstack/svelte-table": "^9.0.0-beta.15", "@tsconfig/svelte": "^5.0.8", "svelte": "^5.56.2", "svelte-check": "^4.6.0", diff --git a/examples/svelte/virtualized-columns/package.json b/examples/svelte/virtualized-columns/package.json index 96ffdc7c3d..829a0146c5 100644 --- a/examples/svelte/virtualized-columns/package.json +++ b/examples/svelte/virtualized-columns/package.json @@ -13,7 +13,7 @@ "@faker-js/faker": "^10.4.0", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tanstack/svelte-table": "^9.0.0-beta.12", + "@tanstack/svelte-table": "^9.0.0-beta.15", "@tanstack/svelte-virtual": "^3.13.28", "@tsconfig/svelte": "^5.0.8", "svelte": "^5.56.2", diff --git a/examples/svelte/virtualized-infinite-scrolling/package.json b/examples/svelte/virtualized-infinite-scrolling/package.json index df5fa5df7e..680f36286f 100644 --- a/examples/svelte/virtualized-infinite-scrolling/package.json +++ b/examples/svelte/virtualized-infinite-scrolling/package.json @@ -14,7 +14,7 @@ "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.1.2", "@tanstack/svelte-query": "^6.1.34", - "@tanstack/svelte-table": "^9.0.0-beta.12", + "@tanstack/svelte-table": "^9.0.0-beta.15", "@tanstack/svelte-virtual": "^3.13.28", "@tsconfig/svelte": "^5.0.8", "svelte": "^5.56.2", diff --git a/examples/svelte/virtualized-rows/package.json b/examples/svelte/virtualized-rows/package.json index 188611f214..a711f41f90 100644 --- a/examples/svelte/virtualized-rows/package.json +++ b/examples/svelte/virtualized-rows/package.json @@ -13,7 +13,7 @@ "@faker-js/faker": "^10.4.0", "@rollup/plugin-replace": "^6.0.3", "@sveltejs/vite-plugin-svelte": "^7.1.2", - "@tanstack/svelte-table": "^9.0.0-beta.12", + "@tanstack/svelte-table": "^9.0.0-beta.15", "@tanstack/svelte-virtual": "^3.13.28", "@tsconfig/svelte": "^5.0.8", "svelte": "^5.56.2", diff --git a/examples/svelte/with-tanstack-form/package.json b/examples/svelte/with-tanstack-form/package.json index 8b8a350c5f..7ef8951b57 100644 --- a/examples/svelte/with-tanstack-form/package.json +++ b/examples/svelte/with-tanstack-form/package.json @@ -22,7 +22,7 @@ "dependencies": { "@tanstack/form-core": "^1.33.0", "@tanstack/svelte-form": "^1.33.0", - "@tanstack/svelte-table": "^9.0.0-beta.12", + "@tanstack/svelte-table": "^9.0.0-beta.15", "zod": "^4.4.3" } } diff --git a/examples/svelte/with-tanstack-query/package.json b/examples/svelte/with-tanstack-query/package.json index 4708e96de2..77079b592c 100644 --- a/examples/svelte/with-tanstack-query/package.json +++ b/examples/svelte/with-tanstack-query/package.json @@ -21,6 +21,6 @@ }, "dependencies": { "@tanstack/svelte-query": "^6.1.34", - "@tanstack/svelte-table": "^9.0.0-beta.12" + "@tanstack/svelte-table": "^9.0.0-beta.15" } } diff --git a/examples/vanilla/basic/package.json b/examples/vanilla/basic/package.json index 24a8f539c2..fbeb03bdf0 100644 --- a/examples/vanilla/basic/package.json +++ b/examples/vanilla/basic/package.json @@ -15,6 +15,6 @@ "vite": "^8.0.16" }, "dependencies": { - "@tanstack/table-core": "^9.0.0-beta.12" + "@tanstack/table-core": "^9.0.0-beta.15" } } diff --git a/examples/vanilla/pagination/package.json b/examples/vanilla/pagination/package.json index 44689445f2..9d05da08e6 100644 --- a/examples/vanilla/pagination/package.json +++ b/examples/vanilla/pagination/package.json @@ -15,6 +15,6 @@ "vite": "^8.0.16" }, "dependencies": { - "@tanstack/table-core": "^9.0.0-beta.12" + "@tanstack/table-core": "^9.0.0-beta.15" } } diff --git a/examples/vanilla/sorting/package.json b/examples/vanilla/sorting/package.json index dfa0889590..3e6c994352 100644 --- a/examples/vanilla/sorting/package.json +++ b/examples/vanilla/sorting/package.json @@ -15,6 +15,6 @@ "vite": "^8.0.16" }, "dependencies": { - "@tanstack/table-core": "^9.0.0-beta.12" + "@tanstack/table-core": "^9.0.0-beta.15" } } diff --git a/examples/vue/basic-external-atoms/package.json b/examples/vue/basic-external-atoms/package.json index 6853ccc27e..3a429cdc4c 100644 --- a/examples/vue/basic-external-atoms/package.json +++ b/examples/vue/basic-external-atoms/package.json @@ -12,8 +12,8 @@ "@faker-js/faker": "^10.4.0", "@tanstack/vue-devtools": "^0.2.19", "@tanstack/vue-store": "^0.11.0", - "@tanstack/vue-table": "^9.0.0-beta.12", - "@tanstack/vue-table-devtools": "^9.0.0-beta.12", + "@tanstack/vue-table": "^9.0.0-beta.15", + "@tanstack/vue-table-devtools": "^9.0.0-beta.15", "vue": "^3.5.35" }, "devDependencies": { diff --git a/examples/vue/basic-external-state/package.json b/examples/vue/basic-external-state/package.json index 9cc30afa6b..b91b91485b 100644 --- a/examples/vue/basic-external-state/package.json +++ b/examples/vue/basic-external-state/package.json @@ -11,8 +11,8 @@ "dependencies": { "@faker-js/faker": "^10.4.0", "@tanstack/vue-devtools": "^0.2.19", - "@tanstack/vue-table": "^9.0.0-beta.12", - "@tanstack/vue-table-devtools": "^9.0.0-beta.12", + "@tanstack/vue-table": "^9.0.0-beta.15", + "@tanstack/vue-table-devtools": "^9.0.0-beta.15", "vue": "^3.5.35" }, "devDependencies": { diff --git a/examples/vue/basic-use-app-table/package.json b/examples/vue/basic-use-app-table/package.json index fc89543bb5..ce3be9eeb6 100644 --- a/examples/vue/basic-use-app-table/package.json +++ b/examples/vue/basic-use-app-table/package.json @@ -10,8 +10,8 @@ }, "dependencies": { "@tanstack/vue-devtools": "^0.2.19", - "@tanstack/vue-table": "^9.0.0-beta.12", - "@tanstack/vue-table-devtools": "^9.0.0-beta.12", + "@tanstack/vue-table": "^9.0.0-beta.15", + "@tanstack/vue-table-devtools": "^9.0.0-beta.15", "vue": "^3.5.35" }, "devDependencies": { diff --git a/examples/vue/basic-use-table/package.json b/examples/vue/basic-use-table/package.json index e42d67177c..7875e09f89 100644 --- a/examples/vue/basic-use-table/package.json +++ b/examples/vue/basic-use-table/package.json @@ -10,8 +10,8 @@ }, "dependencies": { "@tanstack/vue-devtools": "^0.2.19", - "@tanstack/vue-table": "^9.0.0-beta.12", - "@tanstack/vue-table-devtools": "^9.0.0-beta.12", + "@tanstack/vue-table": "^9.0.0-beta.15", + "@tanstack/vue-table-devtools": "^9.0.0-beta.15", "vue": "^3.5.35" }, "devDependencies": { diff --git a/examples/vue/column-groups/package.json b/examples/vue/column-groups/package.json index 5f9ea0307d..727ed1f86c 100644 --- a/examples/vue/column-groups/package.json +++ b/examples/vue/column-groups/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/vue-table": "^9.0.0-beta.12", + "@tanstack/vue-table": "^9.0.0-beta.15", "vue": "^3.5.35" }, "devDependencies": { diff --git a/examples/vue/column-ordering/package.json b/examples/vue/column-ordering/package.json index 947c6ea183..2793bb04b9 100644 --- a/examples/vue/column-ordering/package.json +++ b/examples/vue/column-ordering/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/vue-table": "^9.0.0-beta.12", + "@tanstack/vue-table": "^9.0.0-beta.15", "vue": "^3.5.35" }, "devDependencies": { diff --git a/examples/vue/column-pinning-split/package.json b/examples/vue/column-pinning-split/package.json index 13cdf0a938..84b4e48d82 100644 --- a/examples/vue/column-pinning-split/package.json +++ b/examples/vue/column-pinning-split/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/vue-table": "^9.0.0-beta.12", + "@tanstack/vue-table": "^9.0.0-beta.15", "vue": "^3.5.35" }, "devDependencies": { diff --git a/examples/vue/column-pinning-sticky/package.json b/examples/vue/column-pinning-sticky/package.json index a5dad0c8a4..ff30068a86 100644 --- a/examples/vue/column-pinning-sticky/package.json +++ b/examples/vue/column-pinning-sticky/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/vue-table": "^9.0.0-beta.12", + "@tanstack/vue-table": "^9.0.0-beta.15", "vue": "^3.5.35" }, "devDependencies": { diff --git a/examples/vue/column-pinning/package.json b/examples/vue/column-pinning/package.json index d25ec84e2c..f2939883b9 100644 --- a/examples/vue/column-pinning/package.json +++ b/examples/vue/column-pinning/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/vue-table": "^9.0.0-beta.12", + "@tanstack/vue-table": "^9.0.0-beta.15", "vue": "^3.5.35" }, "devDependencies": { diff --git a/examples/vue/column-resizing-performant/package.json b/examples/vue/column-resizing-performant/package.json index b7507f956b..e4f3480a86 100644 --- a/examples/vue/column-resizing-performant/package.json +++ b/examples/vue/column-resizing-performant/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/vue-table": "^9.0.0-beta.12", + "@tanstack/vue-table": "^9.0.0-beta.15", "vue": "^3.5.35" }, "devDependencies": { diff --git a/examples/vue/column-resizing/package.json b/examples/vue/column-resizing/package.json index fe129518a8..02ecfbcf74 100644 --- a/examples/vue/column-resizing/package.json +++ b/examples/vue/column-resizing/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/vue-table": "^9.0.0-beta.12", + "@tanstack/vue-table": "^9.0.0-beta.15", "vue": "^3.5.35" }, "devDependencies": { diff --git a/examples/vue/column-sizing/package.json b/examples/vue/column-sizing/package.json index 4363c1cd0d..5808f85fa0 100644 --- a/examples/vue/column-sizing/package.json +++ b/examples/vue/column-sizing/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/vue-table": "^9.0.0-beta.12", + "@tanstack/vue-table": "^9.0.0-beta.15", "vue": "^3.5.35" }, "devDependencies": { diff --git a/examples/vue/column-visibility/package.json b/examples/vue/column-visibility/package.json index 49325a0a3b..25429838a6 100644 --- a/examples/vue/column-visibility/package.json +++ b/examples/vue/column-visibility/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/vue-table": "^9.0.0-beta.12", + "@tanstack/vue-table": "^9.0.0-beta.15", "vue": "^3.5.35" }, "devDependencies": { diff --git a/examples/vue/composable-tables/package.json b/examples/vue/composable-tables/package.json index 62603048c8..a540c3e7e5 100644 --- a/examples/vue/composable-tables/package.json +++ b/examples/vue/composable-tables/package.json @@ -11,8 +11,8 @@ "dependencies": { "@tanstack/vue-devtools": "^0.2.19", "@tanstack/vue-store": "^0.11.0", - "@tanstack/vue-table": "^9.0.0-beta.12", - "@tanstack/vue-table-devtools": "^9.0.0-beta.12", + "@tanstack/vue-table": "^9.0.0-beta.15", + "@tanstack/vue-table-devtools": "^9.0.0-beta.15", "vue": "^3.5.35" }, "devDependencies": { diff --git a/examples/vue/composable-tables/src/components/IndeterminateCheckbox.vue b/examples/vue/composable-tables/src/components/IndeterminateCheckbox.vue new file mode 100644 index 0000000000..7ea24e9f0d --- /dev/null +++ b/examples/vue/composable-tables/src/components/IndeterminateCheckbox.vue @@ -0,0 +1,28 @@ + + + diff --git a/examples/vue/composable-tables/src/components/ProductsTable.vue b/examples/vue/composable-tables/src/components/ProductsTable.vue index 35d811cbd2..58eaa61cad 100644 --- a/examples/vue/composable-tables/src/components/ProductsTable.vue +++ b/examples/vue/composable-tables/src/components/ProductsTable.vue @@ -10,6 +10,11 @@ const columnHelper = createAppColumnHelper() const data = ref(makeProductData(1_000)) const columns = columnHelper.columns([ + columnHelper.display({ + id: 'select', + header: ({ header }) => header.SelectAllHeader, + cell: ({ cell }) => cell.SelectCell, + }), columnHelper.accessor('name', { header: 'Product', footer: (props) => props.column.id, @@ -48,6 +53,7 @@ function stressTest() { const table = useAppTable({ key: 'products-table', // needed for devtools debugTable: true, + enableRowSelection: true, columns, data, initialState: { @@ -71,75 +77,79 @@ useTanStackTableDevtools(table) :onStressTest="stressTest" /> - - - - +
+ + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - -
- -
- -
+ +
- -
+ + + + + + + + + diff --git a/examples/vue/composable-tables/src/components/UsersTable.vue b/examples/vue/composable-tables/src/components/UsersTable.vue index 9295bed4dd..1ed3ec5acb 100644 --- a/examples/vue/composable-tables/src/components/UsersTable.vue +++ b/examples/vue/composable-tables/src/components/UsersTable.vue @@ -10,6 +10,11 @@ const columnHelper = createAppColumnHelper() const data = ref(makeData(1_000)) const columns = columnHelper.columns([ + columnHelper.display({ + id: 'select', + header: ({ header }) => header.SelectAllHeader, + cell: ({ cell }) => cell.SelectCell, + }), columnHelper.accessor('firstName', { header: 'First Name', footer: (props) => props.column.id, @@ -58,6 +63,7 @@ function stressTest() { const table = useAppTable({ key: 'users-table', // needed for devtools debugTable: true, + enableRowSelection: true, columns, data, initialState: { @@ -89,85 +95,90 @@ function tableSelector(state: ReturnType) { :onStressTest="stressTest" /> - - - - +
+ + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - -
- -
- -
+ +
- -
+ + + + + + + + + diff --git a/examples/vue/composable-tables/src/components/cell-components.ts b/examples/vue/composable-tables/src/components/cell-components.ts index bacd92252e..b39e149cbb 100644 --- a/examples/vue/composable-tables/src/components/cell-components.ts +++ b/examples/vue/composable-tables/src/components/cell-components.ts @@ -1,5 +1,27 @@ import { defineComponent, h } from 'vue' import { useCellContext } from '../hooks/table' +import IndeterminateCheckbox from './IndeterminateCheckbox.vue' + +// Row-selection checkbox cell - toggles selection for the current row. +// Vue tracks the reactive table state natively, so no Subscribe boundary is +// needed for the checkbox to update when the row-selection state changes. +export const SelectCell = defineComponent({ + name: 'SelectCell', + setup() { + const cell = useCellContext() + return () => { + const row = cell.row + return h('div', { class: 'column-toggle-row' }, [ + h(IndeterminateCheckbox, { + checked: row.getIsSelected(), + disabled: !row.getCanSelect(), + indeterminate: row.getIsSomeSelected(), + onChange: row.getToggleSelectedHandler(), + }), + ]) + } + }, +}) export const TextCell = defineComponent({ name: 'TextCell', diff --git a/examples/vue/composable-tables/src/components/header-components.ts b/examples/vue/composable-tables/src/components/header-components.ts index 5cb64d8667..af6d826783 100644 --- a/examples/vue/composable-tables/src/components/header-components.ts +++ b/examples/vue/composable-tables/src/components/header-components.ts @@ -1,5 +1,22 @@ import { computed, defineComponent, h } from 'vue' import { useHeaderContext } from '../hooks/table' +import IndeterminateCheckbox from './IndeterminateCheckbox.vue' + +// Select-all checkbox used in the header of the row-selection column. +export const SelectAllHeader = defineComponent({ + name: 'SelectAllHeader', + setup() { + const header = useHeaderContext() + return () => { + const table = header.getContext().table + return h(IndeterminateCheckbox, { + checked: table.getIsAllRowsSelected(), + indeterminate: table.getIsSomeRowsSelected(), + onChange: table.getToggleAllRowsSelectedHandler(), + }) + } + }, +}) export const SortIndicator = defineComponent({ name: 'SortIndicator', diff --git a/examples/vue/composable-tables/src/hooks/table.ts b/examples/vue/composable-tables/src/hooks/table.ts index 3fd438e13d..a94114613e 100644 --- a/examples/vue/composable-tables/src/hooks/table.ts +++ b/examples/vue/composable-tables/src/hooks/table.ts @@ -7,6 +7,7 @@ import { filterFns, globalFilteringFeature, rowPaginationFeature, + rowSelectionFeature, rowSortingFeature, sortFns, tableFeatures, @@ -17,6 +18,7 @@ import { PriceCell, ProgressCell, RowActionsCell, + SelectCell, StatusCell, TextCell, } from '../components/cell-components' @@ -24,6 +26,7 @@ import { ColumnFilter, FooterColumnId, FooterSum, + SelectAllHeader, SortIndicator, } from '../components/header-components' import { @@ -47,6 +50,7 @@ const features = tableFeatures({ columnFilteringFeature, globalFilteringFeature, rowPaginationFeature, + rowSelectionFeature, rowSortingFeature, filteredRowModel: createFilteredRowModel(), paginatedRowModel: createPaginatedRowModel(), @@ -71,12 +75,14 @@ const _hook = createTableHook({ RowActionsCell, PriceCell, CategoryCell, + SelectCell, }, headerComponents: { SortIndicator, ColumnFilter, FooterColumnId, FooterSum, + SelectAllHeader, }, }) diff --git a/examples/vue/composable-tables/src/index.css b/examples/vue/composable-tables/src/index.css index 4d8fef0142..b171dde3f0 100644 --- a/examples/vue/composable-tables/src/index.css +++ b/examples/vue/composable-tables/src/index.css @@ -35,6 +35,18 @@ tfoot th { font-weight: normal; } +.table-scroll { + max-height: 400px; + overflow: auto; + border: 1px solid lightgray; +} + +.table-scroll thead th { + position: sticky; + top: 0; + z-index: 1; +} + .table-container { padding: 16px; max-width: 1200px; diff --git a/examples/vue/expanding/package.json b/examples/vue/expanding/package.json index fe8b9a72ed..c790ba1d95 100644 --- a/examples/vue/expanding/package.json +++ b/examples/vue/expanding/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/vue-table": "^9.0.0-beta.12", + "@tanstack/vue-table": "^9.0.0-beta.15", "vue": "^3.5.35" }, "devDependencies": { diff --git a/examples/vue/filters-faceted/package.json b/examples/vue/filters-faceted/package.json index 405aa49464..3bcbd88cdf 100644 --- a/examples/vue/filters-faceted/package.json +++ b/examples/vue/filters-faceted/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/vue-table": "^9.0.0-beta.12", + "@tanstack/vue-table": "^9.0.0-beta.15", "vue": "^3.5.35" }, "devDependencies": { diff --git a/examples/vue/filters-fuzzy/package.json b/examples/vue/filters-fuzzy/package.json index 8c28bd0b13..d4214bd60a 100644 --- a/examples/vue/filters-fuzzy/package.json +++ b/examples/vue/filters-fuzzy/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/vue-table": "^9.0.0-beta.12", + "@tanstack/vue-table": "^9.0.0-beta.15", "vue": "^3.5.35" }, "devDependencies": { diff --git a/examples/vue/filters/package.json b/examples/vue/filters/package.json index 887d2cad6c..411b189a00 100644 --- a/examples/vue/filters/package.json +++ b/examples/vue/filters/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/vue-table": "^9.0.0-beta.12", + "@tanstack/vue-table": "^9.0.0-beta.15", "vue": "^3.5.35" }, "devDependencies": { diff --git a/examples/vue/grouping/package.json b/examples/vue/grouping/package.json index ccfac7ce78..82effd6077 100644 --- a/examples/vue/grouping/package.json +++ b/examples/vue/grouping/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/vue-table": "^9.0.0-beta.12", + "@tanstack/vue-table": "^9.0.0-beta.15", "vue": "^3.5.35" }, "devDependencies": { diff --git a/examples/vue/kitchen-sink/package.json b/examples/vue/kitchen-sink/package.json index 4444fa9841..768d40ef0b 100644 --- a/examples/vue/kitchen-sink/package.json +++ b/examples/vue/kitchen-sink/package.json @@ -12,8 +12,8 @@ "@faker-js/faker": "^10.4.0", "@tanstack/match-sorter-utils": "^9.0.0-beta.0", "@tanstack/vue-devtools": "^0.2.19", - "@tanstack/vue-table": "^9.0.0-beta.12", - "@tanstack/vue-table-devtools": "^9.0.0-beta.12", + "@tanstack/vue-table": "^9.0.0-beta.15", + "@tanstack/vue-table-devtools": "^9.0.0-beta.15", "vue": "^3.5.35" }, "devDependencies": { diff --git a/examples/vue/pagination/package.json b/examples/vue/pagination/package.json index 31430fd04f..08044364a2 100644 --- a/examples/vue/pagination/package.json +++ b/examples/vue/pagination/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/vue-table": "^9.0.0-beta.12", + "@tanstack/vue-table": "^9.0.0-beta.15", "vue": "^3.5.35" }, "devDependencies": { diff --git a/examples/vue/row-pinning/package.json b/examples/vue/row-pinning/package.json index 0e5485f89f..cbdc501728 100644 --- a/examples/vue/row-pinning/package.json +++ b/examples/vue/row-pinning/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/vue-table": "^9.0.0-beta.12", + "@tanstack/vue-table": "^9.0.0-beta.15", "vue": "^3.5.35" }, "devDependencies": { diff --git a/examples/vue/row-selection/package.json b/examples/vue/row-selection/package.json index bb04a58c16..324373adb4 100644 --- a/examples/vue/row-selection/package.json +++ b/examples/vue/row-selection/package.json @@ -11,8 +11,8 @@ "dependencies": { "@faker-js/faker": "^10.4.0", "@tanstack/vue-devtools": "^0.2.19", - "@tanstack/vue-table": "^9.0.0-beta.12", - "@tanstack/vue-table-devtools": "^9.0.0-beta.12", + "@tanstack/vue-table": "^9.0.0-beta.15", + "@tanstack/vue-table-devtools": "^9.0.0-beta.15", "vue": "^3.5.35" }, "devDependencies": { diff --git a/examples/vue/sorting/package.json b/examples/vue/sorting/package.json index d7b91d531e..b7471029d6 100644 --- a/examples/vue/sorting/package.json +++ b/examples/vue/sorting/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/vue-table": "^9.0.0-beta.12", + "@tanstack/vue-table": "^9.0.0-beta.15", "vue": "^3.5.35" }, "devDependencies": { diff --git a/examples/vue/sub-components/package.json b/examples/vue/sub-components/package.json index 879c1153b2..aa95ae9d2c 100644 --- a/examples/vue/sub-components/package.json +++ b/examples/vue/sub-components/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/vue-table": "^9.0.0-beta.12", + "@tanstack/vue-table": "^9.0.0-beta.15", "vue": "^3.5.35" }, "devDependencies": { diff --git a/examples/vue/virtualized-columns/package.json b/examples/vue/virtualized-columns/package.json index f38b7c56a8..cca6d03221 100644 --- a/examples/vue/virtualized-columns/package.json +++ b/examples/vue/virtualized-columns/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/vue-table": "^9.0.0-beta.12", + "@tanstack/vue-table": "^9.0.0-beta.15", "@tanstack/vue-virtual": "^3.13.28", "vue": "^3.5.35" }, diff --git a/examples/vue/virtualized-infinite-scrolling/package.json b/examples/vue/virtualized-infinite-scrolling/package.json index 70866d9c19..c4c347ecc8 100644 --- a/examples/vue/virtualized-infinite-scrolling/package.json +++ b/examples/vue/virtualized-infinite-scrolling/package.json @@ -13,7 +13,7 @@ "@tanstack/match-sorter-utils": "^9.0.0-beta.0", "@tanstack/vue-query": "^5.101.0", "@tanstack/vue-store": "^0.11.0", - "@tanstack/vue-table": "^9.0.0-beta.12", + "@tanstack/vue-table": "^9.0.0-beta.15", "@tanstack/vue-virtual": "^3.13.28", "vue": "^3.5.35" }, diff --git a/examples/vue/virtualized-rows/package.json b/examples/vue/virtualized-rows/package.json index c41c027aca..cc04ced6b5 100644 --- a/examples/vue/virtualized-rows/package.json +++ b/examples/vue/virtualized-rows/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@faker-js/faker": "^10.4.0", - "@tanstack/vue-table": "^9.0.0-beta.12", + "@tanstack/vue-table": "^9.0.0-beta.15", "@tanstack/vue-virtual": "^3.13.28", "vue": "^3.5.35" }, diff --git a/examples/vue/with-tanstack-form/package.json b/examples/vue/with-tanstack-form/package.json index 56c2715e9f..1ff4825f51 100644 --- a/examples/vue/with-tanstack-form/package.json +++ b/examples/vue/with-tanstack-form/package.json @@ -11,7 +11,7 @@ "dependencies": { "@faker-js/faker": "^10.4.0", "@tanstack/vue-form": "^1.33.0", - "@tanstack/vue-table": "^9.0.0-beta.12", + "@tanstack/vue-table": "^9.0.0-beta.15", "vue": "^3.5.35", "zod": "^4.4.3" }, diff --git a/examples/vue/with-tanstack-query/package.json b/examples/vue/with-tanstack-query/package.json index c6f5e7d51a..d4e7838176 100644 --- a/examples/vue/with-tanstack-query/package.json +++ b/examples/vue/with-tanstack-query/package.json @@ -13,7 +13,7 @@ "@tanstack/match-sorter-utils": "^9.0.0-beta.0", "@tanstack/vue-query": "^5.101.0", "@tanstack/vue-store": "^0.11.0", - "@tanstack/vue-table": "^9.0.0-beta.12", + "@tanstack/vue-table": "^9.0.0-beta.15", "vue": "^3.5.35" }, "devDependencies": { diff --git a/packages/angular-table-devtools/package.json b/packages/angular-table-devtools/package.json index c1307931ea..38617fe6d7 100644 --- a/packages/angular-table-devtools/package.json +++ b/packages/angular-table-devtools/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/angular-table-devtools", - "version": "9.0.0-beta.12", + "version": "9.0.0-beta.15", "description": "Angular devtools for TanStack Table.", "license": "MIT", "repository": { diff --git a/packages/angular-table/package.json b/packages/angular-table/package.json index 91cecd58c0..b034459fd7 100644 --- a/packages/angular-table/package.json +++ b/packages/angular-table/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/angular-table", - "version": "9.0.0-beta.12", + "version": "9.0.0-beta.15", "description": "Headless UI for building powerful tables & datagrids for Angular.", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/lit-table/package.json b/packages/lit-table/package.json index ee67822d21..1fb68f0596 100644 --- a/packages/lit-table/package.json +++ b/packages/lit-table/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/lit-table", - "version": "9.0.0-beta.12", + "version": "9.0.0-beta.15", "description": "Headless UI for building powerful tables & datagrids for Lit.", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/preact-table-devtools/package.json b/packages/preact-table-devtools/package.json index a1c22a4511..ef57b45958 100644 --- a/packages/preact-table-devtools/package.json +++ b/packages/preact-table-devtools/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/preact-table-devtools", - "version": "9.0.0-beta.12", + "version": "9.0.0-beta.15", "description": "Preact devtools for TanStack Table.", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/preact-table/package.json b/packages/preact-table/package.json index de517f8c2f..40244bab81 100644 --- a/packages/preact-table/package.json +++ b/packages/preact-table/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/preact-table", - "version": "9.0.0-beta.12", + "version": "9.0.0-beta.15", "description": "Headless UI for building powerful tables & datagrids for Preact.", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/preact-table/src/createTableHook.tsx b/packages/preact-table/src/createTableHook.tsx index ee8fadbd0c..9b3e57d057 100644 --- a/packages/preact-table/src/createTableHook.tsx +++ b/packages/preact-table/src/createTableHook.tsx @@ -1,6 +1,6 @@ 'use client' import { createContext } from 'preact' -import { useContext, useMemo } from 'preact/hooks' +import { useContext, useMemo, useRef } from 'preact/hooks' import { createColumnHelper as coreCreateColumnHelper } from '@tanstack/table-core' import { useTable } from './useTable' import { FlexRender } from './FlexRender' @@ -819,6 +819,16 @@ export function createTableHook< selector, ) + // `useTable` returns a fresh `table` reference on every render (required for + // the React Compiler). The App wrapper components below must NOT depend on + // that reference, or they would be recreated each render and Preact would + // remount their entire subtree on every state update (e.g. a controlled + // input in a toolbar would lose focus on each keystroke). Instead we keep + // the components stable (created once) and read the current table from a + // ref that we refresh on every render. + const tableRef = useRef(table) + tableRef.current = table + // AppTable - Root wrapper that provides table context with optional Subscribe const AppTable = useMemo(() => { function AppTableImpl( @@ -833,17 +843,18 @@ export function createTableHook< | AppTablePropsWithSelector, ): ComponentChildren { const { children, selector: appTableSelector } = props as any + const currentTable = tableRef.current return ( - + {appTableSelector ? ( - + {(state: TAppTableSelected) => (children as (state: TAppTableSelected) => ComponentChildren)( state, ) } - + ) : ( children )} @@ -851,7 +862,7 @@ export function createTableHook< ) } return AppTableImpl as AppTableComponent - }, [table]) + }, []) // AppCell - Wraps cell with context, pre-bound cellComponents, and optional Subscribe const AppCell = useMemo(() => { @@ -895,6 +906,7 @@ export function createTableHook< >, ): ComponentChildren { const { cell, children, selector: appCellSelector } = props as any + const currentTable = tableRef.current const extendedCell = Object.assign(cell, { FlexRender: CellFlexRender, ...cellComponents, @@ -903,7 +915,7 @@ export function createTableHook< return ( {appCellSelector ? ( - + {(state: TAppCellSelected) => ( children as ( @@ -915,7 +927,7 @@ export function createTableHook< ) => ComponentChildren )(extendedCell, state) } - + ) : ( ( children as ( @@ -928,7 +940,7 @@ export function createTableHook< ) } return AppCellImpl as AppCellComponent - }, [table]) + }, []) // AppHeader - Wraps header with context, pre-bound headerComponents, and optional Subscribe const AppHeader = useMemo(() => { @@ -972,6 +984,7 @@ export function createTableHook< >, ): ComponentChildren { const { header, children, selector: appHeaderSelector } = props as any + const currentTable = tableRef.current const extendedHeader = Object.assign(header, { FlexRender: HeaderFlexRender, ...headerComponents, @@ -980,7 +993,7 @@ export function createTableHook< return ( {appHeaderSelector ? ( - + {(state: TAppHeaderSelected) => ( children as ( @@ -990,7 +1003,7 @@ export function createTableHook< ) => ComponentChildren )(extendedHeader, state) } - + ) : ( ( children as ( @@ -1007,7 +1020,7 @@ export function createTableHook< TData, THeaderComponents > - }, [table]) + }, []) // AppFooter - Same as AppHeader (footers use Header type) const AppFooter = useMemo(() => { @@ -1051,6 +1064,7 @@ export function createTableHook< >, ): ComponentChildren { const { header, children, selector: appFooterSelector } = props as any + const currentTable = tableRef.current const extendedHeader = Object.assign(header, { FlexRender: FooterFlexRender, ...headerComponents, @@ -1059,7 +1073,7 @@ export function createTableHook< return ( {appFooterSelector ? ( - + {(state: TAppFooterSelected) => ( children as ( @@ -1069,7 +1083,7 @@ export function createTableHook< ) => ComponentChildren )(extendedHeader, state) } - + ) : ( ( children as ( @@ -1086,7 +1100,7 @@ export function createTableHook< TData, THeaderComponents > - }, [table]) + }, []) // Combine everything into the extended table API const extendedTable = useMemo(() => { diff --git a/packages/react-table-devtools/package.json b/packages/react-table-devtools/package.json index a6a3c26c2c..b89a34117b 100644 --- a/packages/react-table-devtools/package.json +++ b/packages/react-table-devtools/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/react-table-devtools", - "version": "9.0.0-beta.12", + "version": "9.0.0-beta.15", "description": "React devtools for TanStack Table.", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/react-table/package.json b/packages/react-table/package.json index 3f59aab9fb..0a9f37c899 100644 --- a/packages/react-table/package.json +++ b/packages/react-table/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/react-table", - "version": "9.0.0-beta.12", + "version": "9.0.0-beta.15", "description": "Headless UI for building powerful tables & datagrids for React.", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/react-table/src/createTableHook.tsx b/packages/react-table/src/createTableHook.tsx index 7f976a2959..5bd8a55be1 100644 --- a/packages/react-table/src/createTableHook.tsx +++ b/packages/react-table/src/createTableHook.tsx @@ -1,6 +1,6 @@ 'use client' /* eslint-disable @eslint-react/no-context-provider */ -import React, { createContext, useContext, useMemo } from 'react' +import React, { createContext, useContext, useMemo, useRef } from 'react' import { createColumnHelper as coreCreateColumnHelper } from '@tanstack/table-core' import { useTable } from './useTable' import { FlexRender } from './FlexRender' @@ -823,6 +823,16 @@ export function createTableHook< selector, ) + // `useTable` returns a fresh `table` reference on every render (required for + // the React Compiler). The App wrapper components below must NOT depend on + // that reference, or they would be recreated each render and React would + // remount their entire subtree on every state update (e.g. a controlled + // input in a toolbar would lose focus on each keystroke). Instead we keep + // the components stable (created once) and read the current table from a + // ref that we refresh on every render. + const tableRef = useRef(table) + tableRef.current = table + // AppTable - Root wrapper that provides table context with optional Subscribe const AppTable = useMemo(() => { function AppTableImpl(props: AppTablePropsWithoutSelector): ReactNode @@ -835,15 +845,16 @@ export function createTableHook< | AppTablePropsWithSelector, ): ReactNode { const { children, selector: appTableSelector } = props + const currentTable = tableRef.current return ( - + {appTableSelector ? ( - + {(state: TAppTableSelected) => (children as (state: TAppTableSelected) => ReactNode)(state) } - + ) : ( children )} @@ -851,7 +862,7 @@ export function createTableHook< ) } return AppTableImpl as AppTableComponent - }, [table]) + }, []) // AppCell - Wraps cell with context, pre-bound cellComponents, and optional Subscribe const AppCell = useMemo(() => { @@ -895,6 +906,7 @@ export function createTableHook< >, ): ReactNode { const { cell, children, selector: appCellSelector } = props as any + const currentTable = tableRef.current const extendedCell = Object.assign(cell, { FlexRender: CellFlexRender, ...cellComponents, @@ -903,7 +915,7 @@ export function createTableHook< return ( {appCellSelector ? ( - + {(state: TAppCellSelected) => ( children as ( @@ -913,7 +925,7 @@ export function createTableHook< ) => ReactNode )(extendedCell, state) } - + ) : ( ( children as ( @@ -926,7 +938,7 @@ export function createTableHook< ) } return AppCellImpl as AppCellComponent - }, [table]) + }, []) // AppHeader - Wraps header with context, pre-bound headerComponents, and optional Subscribe const AppHeader = useMemo(() => { @@ -970,6 +982,7 @@ export function createTableHook< >, ): ReactNode { const { header, children, selector: appHeaderSelector } = props as any + const currentTable = tableRef.current const extendedHeader = Object.assign(header, { FlexRender: HeaderFlexRender, ...headerComponents, @@ -978,7 +991,7 @@ export function createTableHook< return ( {appHeaderSelector ? ( - + {(state: TAppHeaderSelected) => ( children as ( @@ -988,7 +1001,7 @@ export function createTableHook< ) => ReactNode )(extendedHeader, state) } - + ) : ( ( children as ( @@ -1005,7 +1018,7 @@ export function createTableHook< TData, THeaderComponents > - }, [table]) + }, []) // AppFooter - Same as AppHeader (footers use Header type) const AppFooter = useMemo(() => { @@ -1049,6 +1062,7 @@ export function createTableHook< >, ): ReactNode { const { header, children, selector: appFooterSelector } = props as any + const currentTable = tableRef.current const extendedHeader = Object.assign(header, { FlexRender: FooterFlexRender, ...headerComponents, @@ -1057,7 +1071,7 @@ export function createTableHook< return ( {appFooterSelector ? ( - + {(state: TAppFooterSelected) => ( children as ( @@ -1067,7 +1081,7 @@ export function createTableHook< ) => ReactNode )(extendedHeader, state) } - + ) : ( ( children as ( @@ -1084,7 +1098,7 @@ export function createTableHook< TData, THeaderComponents > - }, [table]) + }, []) // Combine everything into the extended table API const extendedTable = useMemo(() => { diff --git a/packages/solid-table-devtools/package.json b/packages/solid-table-devtools/package.json index f142a72fad..5c79a4b643 100644 --- a/packages/solid-table-devtools/package.json +++ b/packages/solid-table-devtools/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/solid-table-devtools", - "version": "9.0.0-beta.12", + "version": "9.0.0-beta.15", "description": "Solid devtools for TanStack Table.", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/solid-table/package.json b/packages/solid-table/package.json index ac05dd54f7..b31d3a36f4 100644 --- a/packages/solid-table/package.json +++ b/packages/solid-table/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/solid-table", - "version": "9.0.0-beta.12", + "version": "9.0.0-beta.15", "description": "Headless UI for building powerful tables & datagrids for Solid.", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/svelte-table/package.json b/packages/svelte-table/package.json index 0a1203e407..041cadcb0c 100644 --- a/packages/svelte-table/package.json +++ b/packages/svelte-table/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/svelte-table", - "version": "9.0.0-beta.12", + "version": "9.0.0-beta.15", "description": "Headless UI for building powerful tables & datagrids for Svelte.", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/table-core/package.json b/packages/table-core/package.json index 77fae4de54..1fac6d65d7 100644 --- a/packages/table-core/package.json +++ b/packages/table-core/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/table-core", - "version": "9.0.0-beta.12", + "version": "9.0.0-beta.15", "description": "Headless UI for building powerful tables & datagrids for TS/JS.", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/table-core/src/core/table/coreTablesFeature.utils.ts b/packages/table-core/src/core/table/coreTablesFeature.utils.ts index 236710a32b..b8a4e60582 100644 --- a/packages/table-core/src/core/table/coreTablesFeature.utils.ts +++ b/packages/table-core/src/core/table/coreTablesFeature.utils.ts @@ -68,7 +68,9 @@ export function table_reset< * Merges new table options with the current resolved options. * * If `options.mergeOptions` is provided, it owns the merge behavior; otherwise - * options are shallow-merged. + * options are shallow-merged. Static options that should never change after + * initialization are restored on a fresh object so framework merge helpers may + * return readonly getter/proxy objects. * * @example * ```ts @@ -82,17 +84,52 @@ export function table_mergeOptions< table: Table_Internal, newOptions: TableOptions, ) { - if (table.options.mergeOptions) { - return table.options.mergeOptions( - table.options as TableOptions, - newOptions, - ) + const { features, atoms, initialState } = table.options + + // simple merge if no mergeOptions is provided - performant + if (!table.options.mergeOptions) { + return { + ...table.options, + ...newOptions, + features, + atoms, + initialState, + } } - return { - ...table.options, - ...newOptions, + // else use the mergeOptions function and preserve getters/setters + const mergedOptions = table.options.mergeOptions( + table.options as TableOptions, + newOptions, + ) + const descriptors: PropertyDescriptorMap = { + ...Object.getOwnPropertyDescriptors(mergedOptions), } + + return Object.defineProperties( + Object.create(Object.getPrototypeOf(mergedOptions)), + { + ...descriptors, + features: { + value: features, + enumerable: true, + configurable: true, + writable: true, + }, + atoms: { + value: atoms, + enumerable: true, + configurable: true, + writable: true, + }, + initialState: { + value: initialState, + enumerable: true, + configurable: true, + writable: true, + }, + }, + ) as TableOptions } /** @@ -117,15 +154,7 @@ export function table_setOptions< updater, table.options as TableOptions, ) - // table static options that should never change after initialization - const { features, atoms, initialState } = table.options - const mergedOptions = Object.assign(table_mergeOptions(table, newOptions), { - // Once the table instance is created those properties should never change after initialization, - // so we assign them back preserving the `table_mergeOptions` object reference - features, - atoms, - initialState, - }) + const mergedOptions = table_mergeOptions(table, newOptions) if (table.optionsStore) { table.optionsStore.set(() => mergedOptions) diff --git a/packages/table-core/src/fns/filterFns.ts b/packages/table-core/src/fns/filterFns.ts index 44c4fb02d2..7e85698890 100644 --- a/packages/table-core/src/fns/filterFns.ts +++ b/packages/table-core/src/fns/filterFns.ts @@ -217,7 +217,10 @@ const filterFn_between = Object.assign( Number(filterValues[0]) > Number(filterValues[1])) || (['', undefined] as Array).includes(filterValues[1]) || filterFn_lessThan(row, columnId, filterValues[1])), - { autoRemove: (val: any) => !val }, + { + autoRemove: (val: any) => + testFalsy(val) || (testFalsy(val[0]) && testFalsy(val[1])), + }, ) /** @@ -238,7 +241,10 @@ const filterFn_betweenInclusive = Object.assign( Number(filterValues[0]) > Number(filterValues[1])) || (['', undefined] as Array).includes(filterValues[1]) || filterFn_lessThanOrEqualTo(row, columnId, filterValues[1])), - { autoRemove: (val: any) => !val }, + { + autoRemove: (val: any) => + testFalsy(val) || (testFalsy(val[0]) && testFalsy(val[1])), + }, ) /** diff --git a/packages/table-core/tests/unit/core/table/constructTable.test.ts b/packages/table-core/tests/unit/core/table/constructTable.test.ts index abb69736b8..038800927d 100644 --- a/packages/table-core/tests/unit/core/table/constructTable.test.ts +++ b/packages/table-core/tests/unit/core/table/constructTable.test.ts @@ -2,6 +2,36 @@ import { describe, expect, it } from 'vitest' import { constructTable, coreFeatures } from '../../../../src' import { storeReactivityBindings } from '../../../../src/store-reactivity-bindings' +function getterOnlyMerge(...sources: Array) { + const target = {} + + for (const source of sources) { + if (!source) { + continue + } + + for (const key of Reflect.ownKeys(source)) { + if (key in target) { + continue + } + + Object.defineProperty(target, key, { + enumerable: true, + get() { + for (let i = sources.length - 1; i >= 0; i--) { + const value = sources[i]?.[key] + if (value !== undefined) { + return value + } + } + }, + }) + } + } + + return target +} + describe('constructTable', () => { it('should create a table with all core table APIs and properties', () => { const table = constructTable({ @@ -46,4 +76,46 @@ describe('constructTable', () => { expect(table).toHaveProperty('setOptions') expect(table).toHaveProperty('store') // state is managed via store in v9 }) + + it('preserves static options without mutating mergeOptions results', () => { + const features = { + ...coreFeatures, + coreReactivityFeature: storeReactivityBindings(), + } + const atoms = {} + const initialState = {} + const data: Array<{ id: number }> = [] + const nextData = [{ id: 1 }] + const nextFeatures = { + ...coreFeatures, + coreReactivityFeature: storeReactivityBindings(), + } + const nextAtoms = {} + const nextInitialState = {} + + const table = constructTable({ + features, + atoms, + initialState, + columns: [], + data, + mergeOptions: (defaultOptions, options) => + getterOnlyMerge(defaultOptions, options) as any, + }) + + expect(() => { + table.setOptions((prev) => ({ + ...prev, + data: nextData, + features: nextFeatures, + atoms: nextAtoms, + initialState: nextInitialState, + })) + }).not.toThrow() + + expect(table.options.data).toBe(nextData) + expect(table.options.features).toBe(features) + expect(table.options.atoms).toBe(atoms) + expect(table.options.initialState).toBe(initialState) + }) }) diff --git a/packages/table-core/tests/unit/fns/filterFns.test.ts b/packages/table-core/tests/unit/fns/filterFns.test.ts index 8b896576f7..1b6f74a092 100644 --- a/packages/table-core/tests/unit/fns/filterFns.test.ts +++ b/packages/table-core/tests/unit/fns/filterFns.test.ts @@ -12,6 +12,7 @@ import { filterFn_lessThan, filterFn_lessThanOrEqualTo, filterFn_weakEquals, + filterFns, } from '../../../src' import { getStaticTestData } from '../../fixtures/data/generateTestData' @@ -512,4 +513,54 @@ describe('Filter Functions', () => { }) }) }) + + describe('Range Filters', () => { + describe('filterFns.between.autoRemove', () => { + const autoRemove = filterFns.between.autoRemove! + + it('should auto-remove when both endpoints are undefined', () => { + expect(autoRemove([undefined, undefined])).toBe(true) + }) + it('should auto-remove when both endpoints are null', () => { + expect(autoRemove([null, null])).toBe(true) + }) + it('should auto-remove when both endpoints are empty strings', () => { + expect(autoRemove(['', ''])).toBe(true) + }) + it('should NOT auto-remove when both endpoints are valid numbers', () => { + expect(autoRemove([5, 10])).toBe(false) + }) + it('should NOT auto-remove when lower bound is 0 (falsy number)', () => { + expect(autoRemove([0, 10])).toBe(false) + }) + it('should NOT auto-remove when only one endpoint is provided', () => { + expect(autoRemove([undefined, 10])).toBe(false) + expect(autoRemove([5, undefined])).toBe(false) + }) + }) + + describe('filterFns.betweenInclusive.autoRemove', () => { + const autoRemove = filterFns.betweenInclusive.autoRemove! + + it('should auto-remove when both endpoints are undefined', () => { + expect(autoRemove([undefined, undefined])).toBe(true) + }) + it('should auto-remove when both endpoints are null', () => { + expect(autoRemove([null, null])).toBe(true) + }) + it('should auto-remove when both endpoints are empty strings', () => { + expect(autoRemove(['', ''])).toBe(true) + }) + it('should NOT auto-remove when both endpoints are valid numbers', () => { + expect(autoRemove([5, 10])).toBe(false) + }) + it('should NOT auto-remove when lower bound is 0 (falsy number)', () => { + expect(autoRemove([0, 10])).toBe(false) + }) + it('should NOT auto-remove when only one endpoint is provided', () => { + expect(autoRemove([undefined, 10])).toBe(false) + expect(autoRemove([5, undefined])).toBe(false) + }) + }) + }) }) diff --git a/packages/table-devtools/package.json b/packages/table-devtools/package.json index ad95dc33db..becd67df9d 100644 --- a/packages/table-devtools/package.json +++ b/packages/table-devtools/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/table-devtools", - "version": "9.0.0-beta.12", + "version": "9.0.0-beta.15", "description": "Devtools for TanStack Table.", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/vue-table-devtools/package.json b/packages/vue-table-devtools/package.json index 83af0d3ae6..9f7696edb1 100644 --- a/packages/vue-table-devtools/package.json +++ b/packages/vue-table-devtools/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/vue-table-devtools", - "version": "9.0.0-beta.12", + "version": "9.0.0-beta.15", "description": "Vue devtools for TanStack Table.", "author": "Tanner Linsley", "license": "MIT", diff --git a/packages/vue-table/package.json b/packages/vue-table/package.json index 3689b556b1..c85d767239 100644 --- a/packages/vue-table/package.json +++ b/packages/vue-table/package.json @@ -1,6 +1,6 @@ { "name": "@tanstack/vue-table", - "version": "9.0.0-beta.12", + "version": "9.0.0-beta.15", "description": "Headless UI for building powerful tables & datagrids for Vue.", "author": "Tanner Linsley", "license": "MIT",