On this page
Customizable select
.form-select already restyles the closed field. Where the
browser implements
appearance: base-select, the open list, caret, and
checkmark use the same tokens — no dropdown script and no third-party
select.
| What runs it | JavaScript | |
|---|---|---|
| Bootstrap 5.3 | No equivalent. A dropdown or a third-party select plugin. | Not in bootstrap.min.js |
| This repo | `appearance: base-select` on `.form-select` | 0 KB |
| Avoid |
|
|---|
appearance: base-select
is Chrome 135+ and Safari 27+. Firefox 149 needs
dom.select.customizable_select.enabled and
layout.css.appearance-base.enabled. Without those, this
page is still a labelled .form-select with the OS menu.
Opting in replaces the native mobile wheel picker with a web-rendered
top-layer list.
How it works
-
Both the
<select>and::picker(select)setappearance: base-select. The closed field keeps Bootstrap’s padding, radius, and colors. The open list reuses.dropdown-menutokens. -
::picker-icondraws the caret from--bs-form-select-bg-img, including dark mode. The SVG background on the closed field is removed so the two do not stack. -
option:checkeduses the dropdown active background and bold text.::checkmarkis extra decoration; it is not exposed to assistive technology. -
Optional
<button><selectedcontent>mirrors the selected option’s markup in the closed field. Browsers that ignore those tags still show the option text. -
<select multiple>andsizeother than1are left on the OS listbox.
Basic
A labelled .form-select. Open it to see the token-styled picker.
<label class="form-label" for="plan">Plan</label>
<select class="form-select" id="plan" name="plan">
<option value="free">Free</option>
<option value="pro" selected>Pro</option>
<option value="team">Team</option>
</select> Sizing
.form-select-sm and .form-select-lg still change the closed field. The picker inherits the control’s font size.
<div class="mb-3">
<label class="form-label" for="city-sm">Small</label>
<select class="form-select form-select-sm" id="city-sm" name="city-sm">
<option>Copenhagen</option>
<option selected>Aarhus</option>
<option>Odense</option>
</select>
</div>
<div>
<label class="form-label" for="city-lg">Large</label>
<select class="form-select form-select-lg" id="city-lg" name="city-lg">
<option>Copenhagen</option>
<option selected>Aarhus</option>
<option>Odense</option>
</select>
</div> Rich options
Icons and a second line in the list. selectedcontent hides .form-select-desc in the closed field. Each option keeps readable text for browsers that strip the markup.
<label class="form-label" for="shipping">Shipping</label>
<select class="form-select" id="shipping" name="shipping">
<button>
<selectedcontent></selectedcontent>
</button>
<option value="standard" aria-label="Standard, 5 to 7 days">
<span aria-hidden="true">📦</span>
<span>
<span>Standard</span>
<span class="form-select-desc">5–7 days</span>
</span>
</option>
<option value="express" selected aria-label="Express, 1 to 2 days">
<span aria-hidden="true">⚡</span>
<span>
<span>Express</span>
<span class="form-select-desc">1–2 days</span>
</span>
</option>
<option value="overnight" aria-label="Overnight, next morning">
<span aria-hidden="true">🌙</span>
<span>
<span>Overnight</span>
<span class="form-select-desc">Next morning</span>
</span>
</option>
</select> Option groups
optgroup with a legend, styled like a dropdown header. The label attribute still works when legend is missing.
<label class="form-label" for="animal">Animal</label>
<select class="form-select" id="animal" name="animal">
<optgroup>
<legend>Domestic</legend>
<option value="cat" selected>Cat</option>
<option value="dog">Dog</option>
</optgroup>
<optgroup>
<legend>Farm</legend>
<option value="chicken">Chicken</option>
<option value="cow">Cow</option>
</optgroup>
</select> Accessibility
Label with <label for> or wrap the control. Keep a name so the value submits.
Decorative icons inside options take aria-hidden="true". If the mirrored rich content would read badly, set aria-label on the option.
::picker-icon and ::checkmark are not in the accessibility tree. Do not put the only meaning of the control in generated content.
The checked option uses background and font-weight, not color alone. Arrow keys still move in one dimension even if the picker is laid out as a grid.
Browser support
| No script | Polyfill | No fallback |
|---|---|---|
appearance: base-select: Chrome 135+, Safari 27+. Firefox 149 behind dom.select.customizable_select.enabled and layout.css.appearance-base.enabled. | None | Marked experimental on the forms page. Without base-select the closed .form-select and the OS picker stay. Rich markup inside <option> is stripped to text. <button> / <selectedcontent> inside the select are ignored. |