Open Closed

Duplicating rendered select drop-down controls in Razor MVC after upgrade to 10.2 #10603


User avatar
0
daniel.worrall@robertsoncooper.com created

After upgrading my Tiered MVC project from 10.1 to 10.2 I get duplicated dropdown select boxes as below:

This happens to every drop-down box across the site with no change to my CSHTML markup.

I think that this is a problem with the LeptonX Theme, and the duplication seems to be happening as a result of a script running within the theme.

I have downgraded to 10.1 and the issue goes away. Performing the upgrade again using the "abp update" command causes the problem to come back, even on a clean branch.

This is the markup used in my CSHTML page: <abp-select asp-for="QuestionGroup.Type" />

This is the rendered output in Chrome:

<div class="mb-3">
<label class="form-label" for="QuestionGroup_Type">Type</label>
<div class="custom-select-wrapper" data-lpx-bound="true" data-lpx-options-built="true">
<select class="form-select form-control valid" data-val="true" data-val-required="The Type field is required." id="QuestionGroup_Type" name="QuestionGroup.Type" aria-describedby="QuestionGroup_Type-error" aria-invalid="false">
<option value="0">None</option>
<option value="1">All</option>
<option selected="selected" value="2">Full</option>
<option value="3">Pulse</option>
</select>
<div class="custom-select-display form-select d-flex justify-content-between align-items-center" role="combobox" aria-haspopup="listbox" aria-expanded="false" aria-controls="custom-select-5" tabindex="0" aria-labelledby="QuestionGroup_Type"><span>Full</span><i class="bi-chevron-down arrow-icon"></i></div><div class="custom-options-container position-absolute w-100 overflow-y-auto custom-scrollbar" role="listbox" id="custom-select-5" data-lpx-delegated="true" style="display: none;"><div class="custom-option" id="custom-select-5-option-0" data-value="0" data-index="0" role="option" aria-selected="false">None</div><div class="custom-option" id="custom-select-5-option-1" data-value="1" data-index="1" role="option" aria-selected="false">All</div><div class="custom-option active focused" id="custom-select-5-option-2" data-value="2" data-index="2" role="option" aria-selected="true">Full</div><div class="custom-option" id="custom-select-5-option-3" data-value="3" data-index="3" role="option" aria-selected="false">Pulse</div></div></div>

<span class="text-danger field-validation-valid" data-valmsg-for="QuestionGroup.Type" data-valmsg-replace="true"></span>
</div>

This is a problem for me because I want to use the new Entity level permissions that you've added in 10.2.

Thanks

Markdown supported.
Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)

9 Answer(s)
  • User Avatar
    0
    enisn created
    Support Team .NET Developer

    Hi

    I've tested with fresh app on version 10.2.0 and LeptonX version is 5.2.0 and couldn't reproduce the exact same problem with your example:

    I confirm that issue was happening in rc.1 version and it was immediately patched, so this stable version shouldn't have this problem. Can you provide me your ABP version and LeponX exact version from your .csproj file?

    Also as far as I see, a newer patch version is live which is 10.2.1 on ABP and 5.2.1 on LeptonX. You can try with the patch version and ensure your bin and obj folders are cleaned to ensure the latest LeptonX package has to be restored.

    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 again,

    I realized you're using your own custom theming, probably you removed some of leptonx styles but not javascript bundles.

    What you are seeing is not the <abp-select> tag helper rendering the field twice. In LeptonX 10.2, select.form-select elements are enhanced with a custom wrapper/display element. The HTML you shared is consistent with that behavior: the original <select> is wrapped in custom-select-wrapper and a custom-select-display element is added next to it.

    The problem is that the original native <select> should then be hidden by the LeptonX theme CSS. When both controls are visible together, it usually means the corresponding LeptonX bootstrap/theme CSS is not taking effect on the page.

    Since this happens for every dropdown on the site, the issue is most likely at the theme asset/layout level rather than in the page markup itself.

    Please check these items:

    1. In the browser Network tab, verify that the active LeptonX theme CSS is loaded successfully, for example ~/Themes/LeptonX/Global/side-menu/css/bootstrap-light.css, bootstrap-dark.css, or bootstrap-dim.css depending on the selected style.
    2. In the browser Styles/Computed pane, inspect the native <select> inside .custom-select-wrapper and check whether the LeptonX rule that hides it is present and whether it is being overridden by another stylesheet.
    3. If you are using a custom layout via LeptonXThemeMvcOptions.ApplicationLayout, or if you have overridden Themes/LeptonX/Layouts/Application/SideMenuLayout.cshtml or TopMenuLayout.cshtml, please compare that layout with the current LeptonX 10.2 layout and make sure the LeptonX style bundle and theme CSS links are still included.
    4. If you have custom CSS in global-styles.css or another bundle, temporarily disable it and test again, because a global override on .form-select / select can cause the native control to remain visible.

    This is also why downgrading to 10.1 makes the problem disappear: the newer LeptonX custom-select enhancement in 10.2 is active, but the CSS that should hide the original select is not being applied correctly in your application.

    If the problem continues after these checks, please send us these details and we can narrow it down quickly:

    1. Whether you override the LeptonX application layout or use a custom ApplicationLayout
    2. A screenshot of the Network tab for the bootstrap-*.css request(s)
    3. A screenshot of the Styles pane for the visible native <select> element
    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

    In the screenshots, I saw you're using your own stylings already. As a workaround I can recommend downgrading only LeptonX package to 5.1 will help you.

      <ItemGroup>
        <PackageReference Include="Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonX" Version="5.1.1" />
      </ItemGroup>
    

    And rest of the ABP references can stay at v10.2 until we find the real problem on your case. Please provide the information that I asked in the previous messages to help us to detect the original source of the problem

    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)
  • User Avatar
    0

    Thanks for your detailed replies.

    I have this morning sorted out some of the CSS issues as your comments reminded me that I was using my own version of the LeptonX theme built from source with colour changes (an old approach from an earlier stage). I have now removed this and updated the global-styles to carry all of my required colour changes etc.

    This has solved the duplication issue as it is now correctly pulling in the updated version of the LeptonX theme from the package.

    However, I now have an issue where the select created as part of the wrapper only contains one item from the original list and not the whole list. I do not get a drop-down when I click the now visible control - because there are no additional items I presume.

    The screenshot below shows the rendered output and that the original select is now display:none. However, you can see from the rest of the rendered code that the other select doesn't have any additional items.

    <div class="custom-select-wrapper" data-lpx-bound="true">
    <select class="form-select form-control" data-val="true" data-val-required="The ReportingTeamFilter field is required." id="ReportingTeamFilter" name="ReportingTeamFilter" data-lpx-sync-bound="true"><option value=""></option><option value="0527e279-28c3-3032-ef1c-3a157e282647">Test</option><option value="290fdaa4-ae31-eeca-a60d-3a157e28fd31">Test2</option><option value="e962e93c-8c48-ac81-5513-3a157e2936f4">Test3</option><option value="8944cb82-9c7e-e346-07fa-3a1b621ef5cc">Empty Team</option><option value="3feac6d1-b29e-f39f-9697-3a1efc56d16d">MGReportTestTeam</option><option value="d81027e9-3d71-f57f-f73d-3a1f9c493249">Operations</option><option value="1042d0db-3b49-daed-0d0d-3a1f9c493355">People Managers</option><option value="7edcc8c3-5481-f491-cbe7-3a1f9c4933b8">Engineering</option><option value="4898973d-7ae8-e84f-08b7-3a1f9c49340f">Product</option><option value="fea0b829-6d5b-dd61-4669-3a1f9c493467">Design</option><option value="cdd38ddb-ebf0-9b68-03cd-3a1f9c4934bb">Finance</option><option value="a66dc2ee-0b6d-0207-f0d1-3a1f9c493510">Marketing</option><option value="b9d88335-b2ba-820b-77c2-3a1f9c493569">Sales</option><option value="68dfe850-684b-fdeb-4d99-3a1f9c4935b8">Customer Success</option><option value="b92ab6d7-1eb8-dcb3-f7ac-3a1f9c49360d">Support</option><option value="39e88c56-dd42-780c-0e25-3a1f9c49365c">Legal</option><option value="16058caa-39b3-7b90-b88a-3a1f9c4936be">IT Services</option><option value="a5453035-03cd-28e7-5229-3a1f9c493709">Data &amp; Insights</option><option value="e623683f-c8c9-d1ec-2dc8-3a1f9c49375f">QA</option><option value="9db59ca0-4a6a-f9a2-02cf-3a1f9c4937b3">Security</option><option value="a632a989-2e16-f3f0-7084-3a1f9c493806">Research</option><option value="814f4888-8c91-a2ee-28f0-3a1f9c493869">Training</option><option value="d360a394-7faa-337c-41e8-3a1f9c4938c4">Facilities</option><option value="274f3d6b-27a9-050b-775a-3a1f9c493916">Procurement</option><option value="f1bd932d-5668-8b00-0efb-3a1f9c49396a">Strategy</option></select><div class="custom-select-display form-select d-flex justify-content-between align-items-center" role="combobox" aria-haspopup="listbox" aria-expanded="false" aria-controls="custom-select-3" tabindex="0" aria-labelledby="ReportingTeamFilter"><span>Test3</span><i class="bi-chevron-down arrow-icon"></i></div><div class="custom-options-container position-absolute w-100 overflow-y-auto custom-scrollbar" role="listbox" id="custom-select-3" data-lpx-delegated="true" style="display: none;"></div></div>
    

    This is different however than for drop-downs that are, for example, in the advanced filter section of a pure ABP page. These seem to have custom-options generated and do correctly display a drop-down:

    I have checked that they are both using the abp-select tag helper.

    Thanks

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

    I don't use a custom layout for sidemenu - these are the only layouts that I override:

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

    I had same issue, and fix it by removing form-select from select class.

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

    The issue appears to be related to me restoring previously stored filter values on page load, which programmatically updates the underlying <select> elements after LeptonX has already initialized its custom FormSelect wrapper.

    On initial page load, LeptonX scans and wraps select.form-select elements based on their state at that moment. Shortly afterwards, our Vue logic restores persisted filter selections via filterState.restoreFilters(), which mutates the source <select> values outside of LeptonX’s initialization lifecycle.

    In our case, this leaves the LeptonX wrapper out of sync with the real <select>: the source control still contains the correct <option> elements, but the generated .custom-options-container remains empty.

    Because a .custom-select-wrapper already exists, LeptonX appears to treat the control as already initialized and does not fully rebuild it.

    I have implemented a workaround for this, but I believe there is an issue in the LeptonX library, as this would otherwise need to be applied anywhere the wrapper becomes stale or incomplete.

    const rebuildLeptonSelect = (select) => {
        const wrapper = select.closest('.custom-select-wrapper');
    
        if (wrapper) {
            wrapper.parentNode.insertBefore(select, wrapper);
            wrapper.remove();
        }
    
        if (window.leptonx?.FormSelect?.processSelect) {
            window.leptonx.FormSelect.processSelect(select);
        }
    };
    
    const refreshAbpSelectWrappers = async () => {
        await nextTick();
    
        document.querySelectorAll('select.form-select').forEach(select => {
            rebuildLeptonSelect(select);
        });
    };
    

    From debugging, the source <select> controls were rendered correctly and contained the expected <option> elements.

    The failure was in the LeptonX FormSelect wrapper state: a .custom-select-wrapper existed, but its .custom-options-container had no .custom-option children. Calling change, syncWrappedSelect, or processSelect alone did not recover the control, because LeptonX treated the existing wrapper as already initialized.

    The only reliable workaround was to remove the existing wrapper and then call leptonx.FormSelect.processSelect(select) to force a clean rebuild.

    This suggests that LeptonX may need a recovery path for stale or partially initialized wrappers.

    Specifically, when processing a select.form-select, if a.custom-select-wrapperalready exists but the .custom-options-container is missing, empty, or inconsistent with the source <select> options, the implementation should tear down the existing wrapper and recreate it using the normal createCustomSelect / buildCustomOptions path, rather than only attempting an incremental sync.

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

    I have the same issue when initial the AIManangment module(in micro-service template it is a service), the related select2 component dropdown will blocked on the UI, effect the data already retrieved via the api calling, below are the UI issue But, sometimes it without this issue when initial a new empty solution from the template.

    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,

    Select2 has a specific issue and we're fixing it in the next patch version of leptonx as soon as possible. I'll deliver other concerns to the design team to work leptonx enhancement to prevent breaking existing applications.

    I'll update the latest state about it. For now, your workaround seems valid until the next patch

    I had same issue, and fix it by removing form-select from select class.

    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.