From 08f60560b232f3f2fd87b126ee5a588788b4e2de Mon Sep 17 00:00:00 2001 From: Kevin Van Cott Date: Fri, 17 Jul 2026 19:32:36 -0500 Subject: [PATCH] fix(table-core): toggle group column visibility --- .../columnVisibilityFeature.utils.ts | 15 ++++- .../columnVisibilityFeature.utils.test.ts | 55 +++++++++++++++++++ 2 files changed, 68 insertions(+), 2 deletions(-) diff --git a/packages/table-core/src/features/column-visibility/columnVisibilityFeature.utils.ts b/packages/table-core/src/features/column-visibility/columnVisibilityFeature.utils.ts index b7a2d9fd2f..c5ea1154f9 100644 --- a/packages/table-core/src/features/column-visibility/columnVisibilityFeature.utils.ts +++ b/packages/table-core/src/features/column-visibility/columnVisibilityFeature.utils.ts @@ -32,7 +32,9 @@ export function getDefaultColumnVisibilityState(): ColumnVisibilityState { * Updates this column's visibility when hiding is allowed. * * Passing `visible` stores that value. Omitting it flips the column's current - * visibility state. Columns that cannot hide are start unchanged. + * visibility state. Group columns update their hideable leaf columns because + * visibility state is keyed by leaf column ids. Columns that cannot hide stay + * unchanged. * * @example * ```ts @@ -47,9 +49,18 @@ export function column_toggleVisibility< if (column_getCanHide(column)) { table_setColumnVisibility(column.table, (old) => { const next = Object.assign(makeObjectMap(), old) - next[column.id] = + const nextVisible = visible ?? !callMemoOrStaticFn(column, 'getIsVisible', column_getIsVisible) + + const leafColumns = column.getLeafColumns() + for (let i = 0; i < leafColumns.length; i++) { + const leafColumn = leafColumns[i]! + if (column_getCanHide(leafColumn)) { + next[leafColumn.id] = nextVisible + } + } + return next }) } diff --git a/packages/table-core/tests/unit/features/column-visibility/columnVisibilityFeature.utils.test.ts b/packages/table-core/tests/unit/features/column-visibility/columnVisibilityFeature.utils.test.ts index bab29b0c1e..24d3c0ad77 100644 --- a/packages/table-core/tests/unit/features/column-visibility/columnVisibilityFeature.utils.test.ts +++ b/packages/table-core/tests/unit/features/column-visibility/columnVisibilityFeature.utils.test.ts @@ -170,6 +170,61 @@ describe('columnVisibilityFeature.utils', () => { expect(result).toEqual({ firstName: true }) }) + it('should toggle hideable leaf columns for a group column', () => { + const onColumnVisibilityChange = vi.fn() + const columns: Array> = [ + { + id: 'name', + columns: [ + { accessorKey: 'firstName', id: 'firstName' }, + { + accessorKey: 'lastName', + id: 'lastName', + enableHiding: false, + }, + ], + }, + ] + const table = constructTable({ + features, + data: generateTestData(1), + columns, + onColumnVisibilityChange, + }) + const groupColumn = table.getColumn('name')! + + column_toggleVisibility(groupColumn, false) + + const result = getUpdaterResult(onColumnVisibilityChange, {}) + expect(result).toEqual({ firstName: false }) + expect(result).not.toHaveProperty('name') + }) + + it('should infer group visibility toggles from its leaf columns', () => { + const onColumnVisibilityChange = vi.fn() + const columns: Array> = [ + { + id: 'name', + columns: [ + { accessorKey: 'firstName', id: 'firstName' }, + { accessorKey: 'lastName', id: 'lastName' }, + ], + }, + ] + const table = constructTable({ + features, + data: generateTestData(1), + columns, + onColumnVisibilityChange, + }) + const groupColumn = table.getColumn('name')! + + column_toggleVisibility(groupColumn) + + const result = getUpdaterResult(onColumnVisibilityChange, {}) + expect(result).toEqual({ firstName: false, lastName: false }) + }) + it('should not toggle when column cannot be hidden', () => { const onColumnVisibilityChange = vi.fn() const table = makeTable(1, {