HTML Customizable Select Elements

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 the name and value attributes.
  • 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>.



Found This Page Useful? Share It!
Get the Latest Tutorials and Updates
Join us on Telegram

Notifications

Updates are enabled for this browser.

Receive new tutorials, articles and learning resources. You can turn updates off anytime.

Test browser code

Use this code in admin to send a test notification to this browser.