Open Closed

LeptonX 5.3+ custom select breaks Bootstrap .input-group (wrapper margin-bottom: 1rem, no .input-group > .form-select sizing) #10824


User avatar
0
brauerj@gc.adventist.org created

Summary

Since 5.3.0, the FormSelect enhancement wraps every select.form-select in a .custom-select-wrapper and renders a .custom-select-display combobox in its place. The accompanying CSS handles several layout contexts explicitly, but not Bootstrap's .input-group — so any input group containing a select renders broken: the group grows 1rem taller than its control, sibling addons and buttons stretch out of alignment, and the select no longer fills the group.

Still present in 5.6.0.

Environment

  • LeptonX 5.3.0, 5.4.0, 5.4.1, 5.5.0, 5.6.0 (checked each stable release — identical)
  • ABP 10.3 → 10.6, Blazor Server; the same CSS ships in the MVC theme
  • All menu variants (side-menu, top-menu, hybrid-menu, public-website) and all flavors (bootstrap-dim.css, bootstrap-dark.css, bootstrap-light.css + .rtl variants)

Reproduction

<div class="input-group input-group-sm" style="width: 220px">
  <select class="form-select form-select-sm">
    <option>Option A</option>
    <option>Option B</option>
  </select>
  <span class="input-group-text">i</span>
</div>

Expected: control and addon the same height and vertically aligned; control fills the remaining width.

Actual: the group is 1rem taller than the control, the addon stretches to the full group height while the control sits at the top, and the control does not fill the group.

Measured on identical markup before and after the upgrade:

| | LeptonX 4.x | LeptonX 5.3+ | |---|---|---| | .input-group height | 24px | 40px | | rendered control | select 90×24, flex: 1 1 auto | .custom-select-display 61×24 inside a display: block wrapper | | .input-group-text height | 24px | 40px (stretched) | | enclosing table row height | 38px | 42px |

Cause

Two rules, from the bootstrap-*.css files in Volo.Abp.AspNetCore.Components.Web.LeptonXTheme (and the equivalents in Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonX):

.custom-select-wrapper { position: relative; margin-bottom: 1rem; }
.custom-select-wrapper > select.form-select { display: none; }
  1. .input-group is a flex row, so the wrapper's margin-bottom: 1rem is added to the row. The group grows by 16px and the sibling .input-group-text / .btn children stretch to the new height while the wrapper does not.
  2. .custom-select-wrapper is now the flex child, so Bootstrap's .input-group > .form-select { flex: 1 1 auto; width: 1% } no longer matches anything and the control does not fill the group.

There is precedent for handling this per context — the CSS already special-cases DataTables, validation state and floating labels:

div.dt-container div.dt-length .custom-select-wrapper {
  display: inline-block; margin-bottom: 0; width: auto; vertical-align: middle;
}
.custom-select-wrapper.is-invalid > .custom-select-display { border-color: #c00d49 !important; }
.form-floating .custom-select-display { height: calc(3.5rem + 2px); ... }

but there is no equivalent for .input-group.

Secondary problem: sizing set on the native select is lost

Because the native <select> is hidden, anything applied to it no longer affects the rendered control:

  • form-select-sm / form-select-lg are not propagated to .custom-select-display, so a small select renders at default size.
  • Inline styles on the select (e.g. style="max-width: 92px") are lost entirely.

This is most visible with component libraries that render the <select> themselves — with Blazorise, <Select Size="Size.Small" Style="max-width: 92px" /> loses both.

There also appears to be no way to opt out of the enhancement, per element or globally.

Suggested fix

Add .input-group handling alongside the existing special cases:

.input-group > .custom-select-wrapper {
  flex: 1 1 auto;
  width: 1%;
  min-width: 0;
  margin-bottom: 0;
}

Ideally also propagate the native select's size class to .custom-select-display, and honor its inline width constraints. An opt-out hook (a class or data- attribute that FormSelect.init skips) would help applications that render selects through a component library.

Workaround

For anyone else hitting this — app CSS that restores the native select:

.custom-select-wrapper { display: contents; }

.custom-select-wrapper > select.form-select { display: block !important; }

body .custom-select-wrapper > .custom-select-display,
body .custom-select-wrapper > .custom-options-container { display: none !important; }

/* `display: contents` makes the native select a flex item of the input group again, but
   Bootstrap's `.input-group > .form-select` selector still cannot match it. */
.input-group > .custom-select-wrapper > select.form-select {
  flex: 1 1 auto;
  width: 1%;
  min-width: 0;
}

The body prefix on the hide rule is necessary: the theme declares .custom-select-wrapper > .custom-select-display { display: flex !important }, so at equal specificity the theme's stylesheet wins if it loads later and the combobox renders alongside the restored native select.

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
    • Add a small LeptonX override in your app stylesheet to special-case Bootstrap .input-group (this fixes both the extra 1rem height and the lost flex sizing caused by .custom-select-wrapper becoming the flex item):
    /* LeptonX 5.3+ FormSelect inside Bootstrap input-group fix */
    .input-group > .custom-select-wrapper {
      flex: 1 1 auto;
      width: 1%;
      min-width: 0;
    
      /* prevent the wrapper's default spacing from increasing the flex row height */
      margin-bottom: 0;
    }
    
    /* optional: make the display fill the wrapper */
    .input-group > .custom-select-wrapper > .custom-select-display {
      width: 100%;
    }
    
    • If you also need sm/lg sizing to match form-select-sm / form-select-lg, add explicit sizing rules for the generated display (because LeptonX hides the native <select> and the size classes don’t affect the visible element):
    /* propagate Bootstrap select sizing to LeptonX display */
    .custom-select-wrapper > select.form-select-sm + .custom-select-display {
      padding-top: .25rem;
      padding-bottom: .25rem;
      font-size: .875rem;
    }
    
    .custom-select-wrapper > select.form-select-lg + .custom-select-display {
      padding-top: .5rem;
      padding-bottom: .5rem;
      font-size: 1.25rem;
    }
    
    • If you need to honor inline width constraints like style="max-width: 92px" applied on the native <select>, CSS alone can’t reliably “copy” inline styles to the generated .custom-select-display. In that case the only deterministic workaround is what you already discovered: restore the native select (or write a tiny JS hook that copies computed width/max-width from the <select> to .custom-select-display after LeptonX initializes).

    No verified source available for this specific .input-group + FormSelect wrapper issue/fix (it’s a theme CSS gap), but the override approach is consistent with ABP’s recommended UI overriding mechanism.

    • https://abp.io/docs/10.3/framework/architecture/modularity/extending/overriding-user-interface

    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
    brauerj@gc.adventist.org created

    Let me know if this is the right place to submit these types of bugs.

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

    Thanks — the workaround is understood; we already landed the equivalent on our side, and I agree that restoring the native select is the only deterministic option once inline widths on the <select> are involved.

    To be clear about the ask, though: this is a report of a gap in the shipped theme CSS, not a request for an app-side workaround. Can it be tracked as a theme bug?

    .custom-select-wrapper { margin-bottom: 1rem } with no .input-group counterpart means every Bootstrap input group containing a select renders misaligned out of the box, in an unmodified template. The CSS already special-cases div.dt-container div.dt-length, .is-invalid / .is-valid and .form-floating, so .input-group looks like an omission rather than a deliberate limitation. It is unchanged across 5.3.0, 5.4.0, 5.4.1, 5.5.0 and 5.6.0.

    Two things would close it properly:

    1. Ship the .input-group > .custom-select-wrapper rule in the theme, rather than having every application add it.
    2. An opt-out hook — a class or data- attribute that FormSelect.init skips — for applications that render selects through a component library (Blazorise, etc.) and need the native element's own classes and inline styles to apply.
    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    Hi,

    Yes, this is the right place for these reports — thanks for the detailed analysis.

    You're right, this is a gap in the theme CSS: there is no rule integrating .custom-select-wrapper into .input-group, unlike the existing DataTables / validation / .form-floating special cases. We'll fix the custom select's .input-group integration in the theme (both the Blazor and MVC packages) in the next patch release, and we'll evaluate the opt-out hook for FormSelect.init together with it, since component-library scenarios like Blazorise need the native element.

    Until the patch is out, this app-side CSS keeps the custom select and restores the group layout:

    .input-group > .custom-select-wrapper {
      flex: 1 1 auto;
      width: 1%;
      min-width: 0;
      margin-bottom: 0;
    }
    
    /* match Bootstrap's corner flattening for grouped controls */
    .input-group > .custom-select-wrapper:not(:first-child) > .custom-select-display {
      border-top-left-radius: 0;
      border-bottom-left-radius: 0;
    }
    
    .input-group > .custom-select-wrapper:not(:last-child) > .custom-select-display {
      border-top-right-radius: 0;
      border-bottom-right-radius: 0;
    }
    

    Your native-select restore is still the right call where inline widths on the <select> matter, so feel free to keep that instead.

    One correction on the sizing point: the .input-group issue is still present in 5.6.0, but the separate form-select-sm / form-select-lg issue was fixed there — the generated display is now styled based on those classes. Inline styles on the native select are still not transferred; an opt-out hook would let those selects stay native and keep their own styles.

    Your ticket has been refunded.

    Thanks

    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.