Skip to content

fix: Sticky Header Stops Working in FluentDataGrid with Virtualize="true" #4102

@denisesagh

Description

@denisesagh

🐛 Bug Report: Sticky Header Stops Working in FluentDataGrid with Virtualize="true"

💻 Repro or Code Sample

@page "/issue"

<h3>Items Übersicht</h3>

<FluentDataGrid Items="_filteredItems.AsQueryable()"
                ItemSize="48"
                Virtualize="true"
                AutoFit="true"
                DisplayMode="DataGridDisplayMode.Table"
                ResizableColumns="true"
                GenerateHeader="GenerateHeaderOption.Sticky">

    <PropertyColumn Width="150px" Property="@(c => c.Id)" Title="ID" Sortable="true" Filtered="_filter.Id != string.Empty">
        <ColumnOptions>
            <div class="search-box">
                <FluentSearch type="search" Autofocus="true"
                                              Immediate="true"
                                              @bind-Value="_filter.Id"
                                              Placeholder="ID ..." />
            </div>
        </ColumnOptions>
    </PropertyColumn>

    <PropertyColumn Width="200px" Property="@(c => c.Title)" Title="Title" Sortable="true" />
    <PropertyColumn Width="100px" Property="@(c => c.Value)" Title="Value" Sortable="true" />
</FluentDataGrid>

@code {
    private List<Item> _allItems = new();
    private List<Item> _filteredItems = new();

    private FilterModel _filter = new();

    protected override void OnInitialized()
    {
        for (int i = 1; i <= 100; i++)
        {
            _allItems.Add(new Item
            {
                Id = $"ID-{i:D3}",
                Title = $"Title {i}",
                Value = i * 10
            });
        }

        _filteredItems = _allItems.ToList();
    }

    protected override void OnAfterRender(bool firstRender)
    {
        if (firstRender)
        {
            _filter.PropertyChanged += (_, __) => ApplyFilter();
        }
    }

    private void ApplyFilter()
    {
        _filteredItems = _allItems
            .Where(item => string.IsNullOrEmpty(_filter.Id) || item.Id.Contains(_filter.Id, StringComparison.OrdinalIgnoreCase))
            .ToList();

        StateHasChanged();
    }

    public class Item
    {
        public string Id { get; set; }
        public string Title { get; set; }
        public int Value { get; set; }
    }

    public class FilterModel : System.ComponentModel.INotifyPropertyChanged
    {
        private string _id = string.Empty;

        public string Id
        {
            get => _id;
            set
            {
                if (_id != value)
                {
                    _id = value;
                    PropertyChanged?.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs(nameof(Id)));
                }
            }
        }

        public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
    }
}

Steps to reproduce:

  1. Populate the grid with enough items to allow scrolling at least twice the height of the grid.
  2. Scroll down the size of the grid
  3. Paste a string into the search input field.

🤔 Expected Behavior
The sticky header should remain visible at the top of the grid while scrolling, and the grid content should remain visible below it.

😯 Current Behavior
When typing or pasting in the filter, the sticky header scrolls with the content instead of staying fixed. Depending on the scroll position, neither the header nor the grid items are visible.

💁 Possible Solution
Investigate how sticky headers interact with virtualized rows when StateHasChanged is triggered from filter input changes.
Adjust header positioning after virtualization re-renders.

🔦 Context
The issue prevents users from seeing the column header and grid content when filtering with large datasets.
Removing Virtualize="true" and adding @bind-Value:after="@(async () => await InvokeAsync(StateHasChanged))" to the Search Field fixes the sticky header but introduces performance issues. Removing Immediate="true" also fixes the issue.

Image

🌍 Your Environment
OS & Device: Windows, PC
Browser: Chrome, Firefox, Edge
.NET Version: 9
Microsoft.FluentUI.AspNetCore.Components Version: 4.12.1
Blazor: Interactive SSR

I’m happy to help investigate or contribute a fix if needed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    closed:not-actionableThere is no action to be taken in response to this issue.needs: author feedbackThe author of this issue needs to respond in order for us to continue investigating this issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions