Modern HTML supports customizable select elements, allowing developers to style more parts of a drop-down control without replacing the native select with a custom JavaScript widget.
The feature builds on the familiar <select> and <option> elements. Supporting browsers can also use a first-child <button>, the <selectedcontent> element, richer option content, and CSS features such as appearance: base-select and ::picker(select).
Basic Customizable Select Structure
A customizable <select> can include a <button> as its first child. The <selectedcontent> element inside that button mirrors the contents of the currently selected <option>.
Example:
<label for="city">Choose a city:</label>
<select id="city">
<button>
<selectedcontent></selectedcontent>
</button>
<option value="indore">Indore</option>
<option value="melbourne">Melbourne</option>
<option value="london">London</option>
</select>
The browser keeps <selectedcontent> synchronized with the selected <option>. You do not need JavaScript just to update the displayed selected value.
Customizable selects are progressive enhancement. Unsupported browsers can still fall back to normal <select> behavior, although advanced styling features may not apply.
Opt In with appearance: base-select
To enable the customizable rendering model, set appearance: base-select on both the <select> and its picker.
select,
::picker(select) {
appearance: base-select;
}
The <select> represents the closed control. The ::picker(select) pseudo-element represents the pop-up picker that contains the options.
Style the Select and Picker Separately
Once the control uses base-select, the closed button area and the drop-down picker can be styled independently.
Example:
select {
min-width: 240px;
padding: 10px;
border: 1px solid #aaa;
border-radius: 8px;
}
::picker(select) {
border: 1px solid #aaa;
border-radius: 8px;
}
option {
padding: 10px;
}
option:checked {
font-weight: bold;
}
This lets you keep native <select> semantics while gaining more control over layout, spacing, borders, backgrounds, and option states.
How selectedcontent Works
The <selectedcontent> element is placed inside the first child <button> of a single <select> control. When the selected <option> changes, the browser clones the option's contents into <selectedcontent>.
This is useful when options contain richer markup such as icons or separate label spans. You can show that richer content inside the picker while presenting a simpler version in the closed control.
<select>
<button>
<selectedcontent></selectedcontent>
</button>
<option value="design">
<span class="icon" aria-hidden="true">[D]</span>
Design
</option>
<option value="code">
<span class="icon" aria-hidden="true">[C]</span>
Development
</option>
</select>
Customize the Selected Value
Because <selectedcontent> contains cloned option content, you can target elements inside it without changing how those same elements appear in the picker.
Example:
selectedcontent .icon {
display: none;
}
option .icon {
margin-right: 0.5rem;
}
This pattern can keep the closed control compact while still showing richer option content in the drop-down list.
Useful CSS Hooks
| Feature | Purpose |
|---|---|
| appearance: base-select | Opts the select into customizable rendering |
| ::picker(select) | Targets the drop-down picker |
| ::picker-icon | Targets the built-in picker arrow |
| :open | Matches the select while its picker is open |
| :checked | Matches the selected option |
| ::checkmark | Targets the selected option's checkmark |
Form Behavior Remains Native
The <select> still participates in forms like an ordinary select control. Its name and selected <option> determine the submitted value, validation still works, and scripts can continue reading the value property.
const city = document.querySelector("#city");
// Read the same value you would read from a classic select.
console.log(city.value);
This is an important advantage over fully custom widgets, which often require extra JavaScript to reproduce keyboard behavior, form submission, and accessibility semantics.
Compatibility and Progressive Enhancement
Customizable <select> features are newer than traditional select styling and are not supported equally in every browser version. Your form should therefore remain usable when advanced features are ignored.
You can use @supports to apply enhanced styles only where they are recognized.
@supports (appearance: base-select) {
select,
::picker(select) {
appearance: base-select;
}
}
Common Mistakes
- Removing native semantics unnecessarily: keep the
<select>,<option>, and<label>structure intact, including thenameandvalueattributes. - Assuming every browser supports the full feature set: test fallback behavior as well as the enhanced design.
- Putting interactive controls inside option content: rich visual content does not mean every nested element should become separately interactive.
- Forgetting a label: customizable styling does not replace accessible form labeling.
Recommended Practices
- Use a standard select as the foundation so the control degrades gracefully.
- Keep option values explicit when visible option content contains multiple elements.
- Use selectedcontent to simplify how the chosen value appears in the closed control.
- Test keyboard navigation, focus indication, zoom, and high-contrast modes after applying custom styles.
Conclusion
Customizable selects bring much more styling control to native HTML form controls. By combining <select>, <option>, a first-child <button>, <selectedcontent>, and base-select styling, you can build richer drop-down interfaces while preserving normal form behavior. Use the feature progressively so unsupported browsers still receive a functional <select>.