Syncfusion Blazor ComboBox Popup Stuck After Adding New Item via NoRecordsTemplate even after calling HidePopupAsync

Hello,

I'm experiencing an issue with the Syncfusion Blazor SfComboBox component. When I add a new item using a button inside the `NoRecordsTemplate` (i.e., when the user types a custom value and clicks "Add New Scenario"), the ComboBox popup sometimes gets stuck and does not close as expected after calling `HidePopupAsync()`.


Repro Details:

- The issue is intermittent and was difficult to reproduce consistently, but it does occur.

- The ComboBox is configured with `AllowCustom`, `AllowFiltering`, and a custom `NoRecordsTemplate` that includes a button to add a new item.

- After adding the new item and calling `HidePopupAsync()`, the popup occasionally remains visible and stuck.


Steps to Reproduce:


Check out the screen recording I have attached on how to repro it in the reply message below.


1. Run the attached repro code in a Blazor Server project in Windows 10, Visual Studio 2022 in .NET 9 and Syncfusion Blazor version 31.1.19

2. Type a new scenario name that does not exist in the ComboBox. For eg: "abc" or whatever you'd like.

3. Click the "Add New Scenario" button

4. Observe that sometimes the ComboBox popup does not close as expected. At this point ComboBox becomes unusable because that popup will never hide and you need to refresh the page. Take a look at screenshot below where that "s" is stuck after adding it.

Image_4979_1765476304017

See I tried deleting it and it still stays there:

Image_6727_1765476997085

It just stays there no matter what I do. Only page refresh fixes this issue:

Image_1344_1765477046801

5. You might have to try many times to observe this. For each attempt, you have to REFRESH the page and try adding item to it. Don't keep on adding items if you don't see the issue on your first try for that page refresh. Refresh the page > Add it, Refresh the page > Add it... until you see the issue. Once it took me 30 tries to catch it. 


Expected Behavior:

After adding a new item and calling `HidePopupAsync()`, the ComboBox popup should always close.


Actual Behavior:

Occasionally, the popup remains open and stuck, requiring extra clicks or page refresh to dismiss.


Repro code:

https://blazorplayground.syncfusion.com/BNhyCVisRIRNXaZl


Please help me fix this issue, and please don't give some hacky workaround. I'd like to have a proper fix for this very annoying issue.


Thank you.


2 Replies

AK Ashish Khanal December 11, 2025 06:38 PM UTC

Repro screen recording:

<see attached file: comboboxbugrepro_798dccd8.gif>


Repro code:

@using Syncfusion.Blazor.DropDowns
@using Syncfusion.Blazor.Buttons
@using System.ComponentModel.DataAnnotations

<h4>ComboBox Popup Bug Repro</h4>

<EditForm Model="@ScenarioInputModel" OnValidSubmit="@OnValidScenarioSubmitAsync">
    <DataAnnotationsValidator />
    <SfComboBox @ref="comboBox"
                TValue="string"
                TItem="ReportScenario"
                DataSource="@Scenarios"
                @bind-Value="ScenarioInputModel.Name"
                AllowCustom="true"
                AllowFiltering="true"
                ShowClearButton="true"
                Placeholder="Enter or select scenario name"
                PopupHeight="200px"
    Width="50%">
        <ComboBoxFieldSettings Text="ScenarioName" Value="ScenarioName" />
        <ComboBoxTemplates TItem="ReportScenario">
            <NoRecordsTemplate>
                @if (string.IsNullOrWhiteSpace(CustomScenario))
                {
                    <div id="nodata">No saved scenarios. Start typing to add new.</div>
                }
                else
                {
                    <div>
                        <div id="nodata">No match found. Add new scenario?</div>
                        <SfButton CssClass="e-outline" style="margin-top: 10px;" OnClick="AddScenarioFromPopup">Add New Scenario</SfButton>
                    </div>
                }
            </NoRecordsTemplate>
        </ComboBoxTemplates>
        <ComboBoxEvents TValue="string" TItem="ReportScenario" ValueChange="OnScenarioChange" OnValueSelect="@OnScenarioSelect" Filtering="OnScenarioFiltering" OnOpen="@OnScenarioOpen" />
    </SfComboBox>
    <ValidationMessage For="@(() => ScenarioInputModel.Name)" />

    <br />

    <SfButton IsPrimary="true">Save</SfButton>
    <SfButton OnClick="DeleteSelected" IsPrimary="true" type="button" disabled="@(!IsScenarioSelected)">Delete</SfButton>
</EditForm>

@code {
    public class ReportScenario
    {
        public int Id { get; set; }
        public bool IsDefault { get; set; }
        public string ScenarioName { get; set; } = default!;
        public List<string> Models { get; set; } = new();
    }

    List<string> SeriesData => new List<string> { "abcrewrwerer", "defeggsddsg" };
    SfComboBox<string, ReportScenario>? comboBox;
    private ControlsInput ControlsInputModel = new();
    private ScenarioInput ScenarioInputModel = new();
    List<ReportScenario> Scenarios = new();
    string? CustomScenario;

    bool IsScenarioSelected =>
        !string.IsNullOrWhiteSpace(ScenarioInputModel.Name) &&
        Scenarios.Any(s => string.Equals(s.ScenarioName, ScenarioInputModel.Name, StringComparison.OrdinalIgnoreCase));

    protected override async Task OnInitializedAsync()
    {
        await Task.Delay(100); // Simulate async load
        await LoadScenariosAsync();
    }

    // Filtering event to capture custom text
    private async Task OnScenarioFiltering(Syncfusion.Blazor.DropDowns.FilteringEventArgs args)
    {
        CustomScenario = args.Text;
        args.PreventDefaultAction = true;

        var query = new Syncfusion.Blazor.Data.Query().Where(
            new Syncfusion.Blazor.Data.WhereFilter()
            {
                Field = "ScenarioName", // If only using string for TItem, this field can be skipped
                Operator = "contains",
                value = args.Text,
                IgnoreCase = true
            }
        );
        query = !string.IsNullOrEmpty(args.Text) ? query : new Syncfusion.Blazor.Data.Query();

        if (comboBox is not null)
            await comboBox.FilterAsync(Scenarios, query);
    }

    // Add scenario from popup button
    private async Task AddScenarioFromPopup()
    {
        if (comboBox is not null && !string.IsNullOrWhiteSpace(CustomScenario))
        {
            // Prevent duplicate scenario names (case-insensitive)
            if (Scenarios.Any(s => string.Equals(s.ScenarioName, CustomScenario, StringComparison.OrdinalIgnoreCase)))
            {
                // Optionally show a message to the user here
                return;
            }

            var customReportScenario = new ReportScenario
            {
                Id = 0, // 0 for new, will be set after DB insert
                ScenarioName = CustomScenario,
                Models = SeriesData.Select(f => f).ToList()
            };

            Scenarios.Add(customReportScenario);

            // Refresh ComboBox UI
            await comboBox.RefreshDataAsync();

            // Set selected value
            ScenarioInputModel.Name = CustomScenario;
            CustomScenario = null;

            await comboBox.HidePopupAsync();
        }
    }

    // Delete selected scenario
    private async Task DeleteSelected()
    {
        if (!IsScenarioSelected)
            return;

        Scenarios.RemoveAll(s => string.Equals(s.ScenarioName, ScenarioInputModel.Name, StringComparison.OrdinalIgnoreCase));
        ScenarioInputModel.Name = null;
        if (comboBox is not null)
            await comboBox.RefreshDataAsync();
    }

    private async Task OnValidScenarioSubmitAsync()
    {

    }

    void OnScenarioChange(ChangeEventArgs<string, ReportScenario> args)
    {

    }

    void OnScenarioSelect(SelectEventArgs<ReportScenario> args)
    {

    }

    private void OnScenarioOpen(Syncfusion.Blazor.DropDowns.BeforeOpenEventArgs args)
    {

    }

    async Task LoadScenariosAsync()
    {
        await Task.Delay(100); // Simulate 100 ms delay
        Scenarios = new List<ReportScenario>();
        //Scenarios = await Task.FromResult(new List<ReportScenario> { });

        var defaultScenario = Scenarios.FirstOrDefault(s => s.IsDefault);

        if (defaultScenario is not null)
        {
            ScenarioInputModel.Name = defaultScenario.ScenarioName;
            ControlsInputModel.StartDate = DateTime.Today;
            ControlsInputModel.EndDate = DateTime.Today.AddDays(6);
        }
        else
        {
            ScenarioInputModel.Name = null;
            ControlsInputModel.StartDate = DateTime.Today;
            ControlsInputModel.EndDate = DateTime.Today.AddDays(6);
        }
    }

    public class ScenarioInput : IValidatableObject
    {
        public string? Name { get; set; }

        public IEnumerable<System.ComponentModel.DataAnnotations.ValidationResult> Validate(System.ComponentModel.DataAnnotations.ValidationContext validationContext)
        {
            if (string.IsNullOrWhiteSpace(Name))
                yield return new System.ComponentModel.DataAnnotations.ValidationResult("Scenario name is required yo", new[] { nameof(Name) });
        }
    }

    public class ControlsInput : IValidatableObject
    {
        public DateTime? StartDate { get; set; } = DateTime.Today;
        public DateTime? EndDate { get; set; } = DateTime.Today.AddDays(6);

        public IEnumerable<System.ComponentModel.DataAnnotations.ValidationResult> Validate(System.ComponentModel.DataAnnotations.ValidationContext validationContext)
        {
            if (StartDate.HasValue && EndDate.HasValue)
            {
                var days = (EndDate.Value.Date - StartDate.Value.Date).TotalDays + 1;
                if (days < 1 || days > 15)
                    yield return new System.ComponentModel.DataAnnotations.ValidationResult("Select a date range under 15 days.", new[] { nameof(EndDate) });
            }
        }
    }
}



Attachment: comboboxbugrepro_798dccd8.gif


KN Kundurthi Naga Siddartha Kundurthi Vennela Prasad Syncfusion Team December 12, 2025 11:19 AM UTC

Hi Ashish Khanal,

 

 

Thank you for sharing the details with us. Based on further testing, we’ve observed that the issue appears to be related to a timing/race condition between RefreshDataAsync() and HidePopupAsync(). A simple workaround that has helped stabilize the behavior is to yield control back to the UI thread before attempting to hide the popup. This can be done by inserting await Task.Yield() before calling HidePopupAsync():

 

This ensures the ComboBox has finished its internal refresh cycle before the popup is closed, reducing the likelihood of the stuck state which you're facing randomly. In our tests, this approach has been more reliable than calling HidePopupAsync() immediately.

 

Scenarios.Add(new ReportScenario { ScenarioName = CustomScenario });

await comboBox.RefreshDataAsync();

SelectedScenario = CustomScenario;

CustomScenario = null;

 

await Task.Yield(); // allow UI render cycle to complete

await comboBox.HidePopupAsync();

 

 

For your reference, we have included a runnable sample along with a GIF demonstration below.

Sample: https://blazorplayground.syncfusion.com/embed/hjreMrMVAxEwCGWa?appbar=true&editor=true&result=true&errorlist=true&theme=bootstrap5

 

Gif:


 

 



Loader.
Up arrow icon