Open Closed

Leptonx select overlay drops optgroup #10623


User avatar
0
rcalv002 created

LeptonX 5.3.0 Custom-Select Overlay Drops <optgroup> and Breaks Inside <Modal> (Blazor Server)

Summary

LeptonX's custom-select overlay (the Bootstrap-style <button class="select-button"> / <ul class="dropdown-menu"> overlay that LeptonX paints over every native <select> / Blazorise <Select> on the page) has two distinct rendering bugs that surface in a Blazor Server app running ABP 10.3.0 + LeptonX 5.3.0 + Blazorise 2.0.4:

  1. <optgroup> headers are dropped — when a Blazorise <Select> contains <SelectGroup> (or a native <select> contains <optgroup>), the overlay flattens all options into a single ungrouped list. The group labels are gone and the user cannot tell which entry belongs to which group.
  2. Options never render when the <Select> is inside a <Modal> — the overlay button paints (showing the placeholder text) but the dropdown panel is empty when opened, no matter how many <SelectItem>s the underlying <select> has. This appears specific to Blazorise modals, where the <select> element is moved/wrapped after LeptonX has run its initial overlay pass.

Environment

| Component | Version | | --- | --- | | .NET | 10.0 | | ABP Framework | 10.3.0 | | Volo.Abp.AspNetCore.Components.Server.LeptonXTheme | 5.3.0 | | Volo.Abp.AspNetCore.Components.Web.LeptonXTheme | 5.3.0 (transitive) | | Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonX | 5.3.0 | | Blazorise | 2.0.4 | | LeptonX layout | LeptonXBlazorLayouts.SideMenu | | Browser | Chrome (latest), reproduced in Edge |

Confirmed on LeptonX 5.3.0 with Blazorise 2.0.4 (our 10.3 baseline), so the bugs are LeptonX-side, not Blazorise.

Bug 1 — <optgroup> headers dropped

Reproduction

  1. ABP Blazor Server 10.3 with the LeptonX SideMenu layout.
  2. Add a Blazorise <Select> outside any modal with grouped options, e.g.:
<Select TValue="string" @bind-Value="@SelectedLayoutCode">
    <SelectItem Value="@string.Empty">Select report or layout</SelectItem>
    @foreach (var reportType in ReportCollection)
    {
        <SelectGroup Label="@reportType.TypeName">
            @foreach (var reportLayout in reportType.ReportLayoutList ?? [])
            {
                <SelectItem Value="@reportLayout.LayoutCode">@reportLayout.LayoutName</SelectItem>
            }
        </SelectGroup>
    }
</Select>
  1. Run the app and open the dropdown.

Expected (and what the underlying <select> actually emits):

[Select report or layout]
─── A/R Aging ───
   AR_Aging_Standard
   AR_Aging_Detailed
─── Sales ───
   Sales_Order_Open
   Sales_Order_Closed

Actual: the overlay strips the group rows; the user sees a flat list:

[Select report or layout]
AR_Aging_Standard
AR_Aging_Detailed
Sales_Order_Open
Sales_Order_Closed

Verification — the underlying DOM is correct

Inspect <select> in DevTools and the <optgroup label="…"> elements are present and well-formed. Native browser <select> rendering (when LeptonX's overlay JS is removed) shows the groups correctly. Bug is in the overlay's DOM walk; it iterates <option> only and ignores <optgroup>.

Affected page in our app

"Reports and Layouts" picker. Layouts are grouped by report type (e.g., A/R Aging, Sales). With the overlay, every layout name appears flattened with no indication of which report family it belongs to.

Bug 2 — <Select> content empty when hosted inside <Modal>

Reproduction

  1. Same project as above.
  2. Place a Blazorise <Select> inside a Blazorise <Modal>:
<Modal @ref="MyModal" Centered="true">
    <ModalContent>
        <ModalBody>
            <Select TValue="string" @bind-Value="@SelectedCurrency">
                <SelectItem Value="">Select currency</SelectItem>
                @foreach (var c in AvailableCurrencies)
                {
                    <SelectItem Value="@c.Code">@c.Code - @c.Name</SelectItem>
                }
            </Select>
        </ModalBody>
    </ModalContent>
</Modal>
  1. Open the modal and click the select.

Expected: the dropdown panel lists every currency.

Actual: the overlay button shows the placeholder ("Select currency"), but the dropdown panel is empty — no <li> rows are rendered, even though the underlying <select> is fully populated.

Verification

  • Inspect the <select> in DevTools while the modal is open: every <option> is present and has the right value/text content.
  • Submit the form by typing in the (functioning) overlay search input or by pressing Tab and arrow keys — keyboard navigation also fails because the overlay's <ul> is empty.
  • Replace the Blazorise <Select> with a native <select class="form-control"> in the same modal: the overlay still paints, but its <ul> is now populated correctly. This is the smoking gun: the overlay successfully consumes a static native <select> but fails when the <select> is the one Blazorise rendered. Our hypothesis is that LeptonX runs its overlay-decoration pass once on modal open, before Blazorise has finished rendering the <select>'s <option> children, and never re-runs after Blazorise's second render pass.

Workaround

Replace Blazorise <Select> with native <select class="form-control"> elements (with explicit @onchange handlers, since @bind does not work the same on native <select> for non-string values). The native <select> keeps its native behaviour underneath the overlay, and either renders correctly (groups visible) or, when LeptonX's overlay still mis-renders, the native control behind it remains usable as a fallback.

Bug 1 workaround (groups)

@* Native <select> — LeptonX's custom-select overlay ignores <optgroup> *@
<select class="form-control" value="@Filter.LayoutCode" @onchange="OnLayoutCodeChanged" disabled="@IsLoading">
    <option value="">@(IsLoading ? L["LoadingWithThreeDot"] : L["SelectReportOrLayout"])</option>
    @foreach (var reportType in ReportCollection)
    {
        <optgroup label="@reportType.TypeName">
            @foreach (var reportLayout in reportType.ReportLayoutList ?? [])
            {
                <option value="@reportLayout.LayoutCode">@reportLayout.LayoutName</option>
            }
        </optgroup>
    }
</select>
private async Task OnLayoutCodeChanged(ChangeEventArgs e)
{
    var layoutCode = e.Value?.ToString() ?? string.Empty;
    Filter.LayoutCode = layoutCode;
    await LoadLayoutParametersAsync(layoutCode);
}

Bug 2 workaround (modal)

@* Native <select> — LeptonX's custom-select overlay breaks inside modals *@
<select class="form-control" value="@NewSyncJob.BaseCurrency" @onchange="OnBaseCurrencyChanged" disabled="@(!AvailableCurrencies.Any())">
    <option value="">@L["SelectCurrency"]</option>
    @foreach (var currency in AvailableCurrencies)
    {
        <option value="@currency.Code">@currency.Code - @currency.Name</option>
    }
</select>
private void OnBaseCurrencyChanged(ChangeEventArgs e)
{
    NewSyncJob.BaseCurrency = e.Value?.ToString() ?? string.Empty;
}

For nullable enums in modals (e.g., DayOfWeek?), the value round-trips as the integer string:

<select class="form-control" value="@((int?)NewSyncJob.SyncDayOfWeek)" @onchange="OnDayOfWeekChanged" disabled="@(NewSyncJob.Frequency != SyncFrequency.Weekly)">
    <option value="">@L["SelectDay"]</option>
    @foreach (var day in Enum.GetValues<DayOfWeek>())
    {
        <option value="@((int)day)">@L[$"Enum:DayOfWeek.{day}"]</option>
    }
</select>
private void OnDayOfWeekChanged(ChangeEventArgs e)
{
    var val = e.Value?.ToString();
    NewSyncJob.SyncDayOfWeek = string.IsNullOrEmpty(val) ? null : (DayOfWeek)int.Parse(val);
}
Markdown supported.
Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)

4 Answer(s)
  • User Avatar
    0
    AI-Bot created
    Support Team ABP Agent

    This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    rcalv002 created

    [AI-Bot] said:


    This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.

    theres no content

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    AI-Bot created
    Support Team ABP Agent

    Please contact us at https://abp.io/contact.


    This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    enisn created
    Support Team .NET Developer

    Hi,

    Thanks for the detailed report and the reproduction steps.

    We reviewed the scenario with ABP 10.3.0, LeptonX 5.3.0, and Blazorise 2.0.4. This matches an issue in the LeptonX custom select overlay rather than a problem with your data binding.

    In the affected LeptonX version, the custom overlay is applied to select.form-select controls and builds its own visible option list from the native <select>. This causes two problems in the scenarios you described:

    • <optgroup> labels are not preserved in the custom overlay, so grouped options are displayed as a flat list.
    • In the Blazorise modal scenario, the native <select> can contain the correct <option> elements while the custom overlay list remains empty or out of sync after the modal/component render cycle.

    We are tracking this in Lepton issue #3488, and the fix is being handled in PR #3491. The fix is targeted for the LeptonX 5.2 patch line and will be available with a 5.2.x patch package after the PR is merged and released.

    You can track issues and releases from here: abp.io/pro-releases

    Until the fix is available in a LeptonX package release, the safest workaround is to avoid the LeptonX custom select overlay for the affected controls:

    • Use a native <select> that does not use the form-select class for grouped selects and modal-hosted selects, for example class="form-control" as you already tried.
    • Keep explicit @onchange handlers for non-string or nullable enum values, because the native select value is received as a string.
    • Scope the workaround only to selects that use <optgroup> or are rendered inside the affected modal flow.

    Your DOM verification is also the right way to confirm the issue: if DevTools shows the expected <option> / <optgroup> nodes in the native select but the LeptonX dropdown is flattened or empty, the problem is in the custom overlay rendering/synchronization layer.

    We will update this ticket when the LeptonX 5.2.x patch package is available. If you still see an empty dropdown with a native select that does not use form-select, please share a minimal component/page that reproduces it, because that would indicate a separate rendering path.


    Since this was confirmed as a product issue in LeptonX, we have refunded your support ticket credit.


    Best regards,

    ABP Support Team

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
Boost Your Development
ABP Live Training
Packages
See Trainings
Mastering ABP Framework Book
The Official Guide
Mastering
ABP Framework
Learn More
Mastering ABP Framework Book
Made with ❤️ on ABP v10.8.0-preview. Updated on September 28, 2026, 11:44
1
ABP Assistant
🔐 You need to be logged in to use the chatbot. Please log in first.