[DataGrid] Add Visible parameter to hide columns without losing their state - #5333
sebguischr wants to merge 2 commits into
Conversation
…their state A column left out with @if is removed from the grid and comes back as a new column: it is placed after all the other columns, and the grid keeps a sort level on the removed instance, so the header no longer shows the sort. ColumnBase.Visible hides a column while keeping it part of the grid. The grid now tracks every collected column (_allColumns) next to the displayed ones (_columns): the column keys, the column order (GetColumnOrder, ColumnOrder, ColumnOrderChanged), the sort by title and the sort restored from the URL use every column, while rendering, indices, pinned offsets and header UI use the displayed ones. Moving a displayed column keeps the place of the hidden ones. The tracks of hidden columns are removed from GridTemplateColumns when it has one track per column. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Copilot review overview
🟢 Approval recommended
The implementation is cohesive and well-covered by new tests, with only a minor test naming mismatch to optionally address.
Review effort: Lite
Findings: 1
Open (1)
What changed in this PR
This PR adds a Visible parameter to DataGrid columns so columns can be hidden without being removed/recreated, preserving column instance state (sort levels, order slots, keys) while omitted from rendering.
Changes:
- Introduced
ColumnBase.Visible(defaulttrue) and updatedFluentDataGridto maintain both “all columns” and “visible columns” collections. - Updated ordering/sorting/keying logic to operate over all collected columns while keeping rendering/layout/index-based behaviors driven by visible columns.
- Added a demo example + documentation and introduced a dedicated bUnit test suite covering visibility behaviors.
| File | Description |
|---|---|
| tests/Core/Components/DataGrid/FluentDataGridColumnVisibilityTests.razor | Adds coverage for hidden-column rendering, sorting, ordering, template tracks, row-details toggle placement, and pinned offsets. |
| src/Core/Components/DataGrid/FluentDataGrid.razor.cs | Implements _allColumns vs _columns split, merges reorders back into _allColumns, and adapts template/pinning/sort resolution accordingly. |
| src/Core/Components/DataGrid/Columns/ColumnBase.razor.cs | Adds the new Visible parameter with XML docs describing behavioral differences vs @if. |
| examples/Demo/FluentUI.Demo.Client/Documentation/Components/DataGrid/Pages/DataGridDynamicColumnsPage.md | Documents the new “Hide columns” approach using Visible. |
| examples/Demo/FluentUI.Demo.Client/Documentation/Components/DataGrid/Examples/DataGridColumnVisibility.razor | Adds a demo sample showing checkbox-driven column visibility while preserving order/sort. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| } | ||
|
|
||
| [Fact] | ||
| public void FluentDataGrid_Visible_False_OnAPinnedColumn_OffsetsTheNextPinnedColumnFromTheEdge() |
There was a problem hiding this comment.
Renamed to FluentDataGrid_Visible_False_OnAPinnedColumn_DoesNotOffsetTheNextPinnedColumn in 3fb04f9.
| internal readonly List<ColumnBase<TGridItem>> _columns; | ||
| // Every collected column in display order, hidden ones (ColumnBase.Visible) included, so that the column order, | ||
| // the sort and the column keys keep holding them while they are hidden. | ||
| internal readonly List<ColumnBase<TGridItem>> _allColumns; |
There was a problem hiding this comment.
I think it's dangerous to have two variables, _columns and _allColumns, where one is a subset of the other: a problem with managing one of these variables versus the other can lead to anomalies that are difficult to detect.
Why not use _columns and have a Get property that returns only the visible columns (Visible == true)?
There was a problem hiding this comment.
Agreed, done in 3fb04f9: there is a single list again.
_columnsholds every collected column, hidden ones included (so column order, keys and sort are back to the original code);- the displayed columns come from an internal
VisibleColumnsproperty. It returns_columnsitself when no column is hidden, so the usual case does not allocate (covered by a test), and the filtered list otherwise; FluentDataGridCell.Columngoes throughGetVisibleColumn(index), which is O(1) when no column is hidden, since it is read several times per cell;- moving a column now writes it back into the places of the displayed unpinned columns of
_columns, so there is no merge between two lists anymore.
The diff is smaller as a result. PR description updated.
…columns Review feedback: two lists, one a subset of the other, can drift apart. _columns holds every collected column again, hidden ones included, and the displayed columns come from the VisibleColumns property, which returns _columns itself when no column is hidden, so the usual case allocates nothing. Column order, keys and sort need no change anymore; rendering, the indices (hidden columns get none), pinned offsets, the grid template, the resize/reorder setup, FluentDataGridCell.Column (GetVisibleColumn, O(1) without hidden columns) and FluentDataGridRow.Columns use the displayed columns. Moving a column writes it back into the places of the displayed unpinned columns, so pinned and hidden columns stay where they are. Also renames a test whose name said the opposite of what it checks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Hi sebguischr, We discussed it and we definitely see value in adding this. But we do want to take some more time to properly analyze the code and solution. We will not merge it in for the final v5 release just yet. |
|
Thanks Vincent Baaij (@vnbaaij), understood, no rush on our side. To give some context on where these PRs come from: we use the DataGrid a lot and would like to help close a few gaps compared to other grids, step by step and in the spirit of the current design (composition rather than built-in features). Column visibility is a first step; next ideas include column footers/summary rows (following up on #273) and a way to save and restore the grid's state (sort, column order, visibility, widths). We'll keep each PR small and focused. For future proposals, would you prefer that we open a discussion or an issue first, to agree on the design before writing code? Happy to adapt to however you like to work. |
|
Having discussions first woud help, yes. That allows for also getting input from others users/developers than just us. We also need to be mindful about maintainability so I can't promise beforehand that all wishes will be granted... |

Pull Request
📖 Description
Adds a
Visibleparameter to DataGrid columns, so that a column can be hidden (for instance from a column chooser) without losing its state.Today the only way to hide a column is to leave it out with
@if(see the "Dynamic columns" demo). The column is then removed from the grid and comes back as a new column, with two side effects (verified with bUnit ondev):aria-sort="none"everywhere).With
Visible="false"the column stays part of the grid:GetColumnOrder(),ColumnOrder,ColumnOrderChangedstill list it), even when the displayed columns are moved in the meantime;SortByColumnAsync(title)/AddSortByColumnAsync(title)and the sort restored from the URL (SaveStateInUrl) still find it.Implementation
_columnsstill holds every collected column in display order, hidden ones included, so the column order, the column keys and the sort are unchanged.VisibleColumnsproperty, which returns_columnsitself when no column is hidden (the usual case allocates nothing), and the filtered list otherwise. Rendering (rows, headers, placeholders, colspans),GridTemplateColumns, pinned offsets, the resize/reorder setup,FluentDataGridCell.ColumnandFluentDataGridRow.Columnsread the displayed columns.Indexis its place among the displayed columns (hidden columns get0).FluentDataGridCell.Columnfinds its column by that index, in O(1) when no column is hidden.GridTemplateColumnshas exactly one track per column, the tracks of hidden columns are removed (spaces insideminmax(...)are handled). Otherwise (e.g.repeat()), it is used as is.Not a breaking change:
Visibledefaults totrue.🎫 Issues
None found.
👩💻 Reviewer Notes
Two questions:
FluentDataGridColumnChoosercomponent (that would also needVisibleChanged)?Smoke test: demo site,
/DataGrid/DynamicColumns, new "Hide columns" section: sort by "Department" (or move a column), uncheck "Department", check it again → it comes back at its place, still sorted.📑 Test Plan
New
FluentDataGridColumnVisibilityTests(10 tests):ColumnOrder/GetColumnOrder()hold the hidden column;GridTemplateColumnsloses the hidden column's track (minmax(...)), or is left as is withrepeat();VisibleColumnsis_columnsitself.All 459 DataGrid tests pass. Checked manually in the demo (Chrome).
✅ Checklist
General
Component-specific
⏭ Next Steps
Depending on the answer to question 2: a "Hide column" header menu item and a column chooser component.
🤖 Generated with Claude Code