DEV Community

Vishal Singh
Vishal Singh

Posted on

Customizable Select: Style Native Dropdowns Without Rebuilding Accessibility

Native <select> elements provide keyboard interaction, form submission, focus behaviour, and platform integration. They are also famously difficult to style.

That tension has pushed many teams to replace a real select with divs, ARIA roles, and a large JavaScript component. The result may match the design system, but it also inherits responsibility for every keyboard, focus, scrolling, and assistive-technology detail.

Customizable select features aim to provide a better middle ground: keep the native element and behaviour while opting into new styling hooks.

Support is still limited. MDN does not classify the complete feature set as Baseline, and framework or server-rendering interactions need testing. Use progressive enhancement rather than replacing every production dropdown immediately.

Opt into the base-select appearance

The central CSS opt-in is appearance: base-select on both the select and its picker.

select,
::picker(select) {
  appearance: base-select;
}
Enter fullscreen mode Exit fullscreen mode

This gives the control browser-defined base behaviour that can be styled more directly.

select {
  min-inline-size: 14rem;
  padding: 0.75rem 1rem;
  border: 1px solid #cbd5e1;
  border-radius: 0.75rem;
  background: white;
  color: #0f172a;
}

::picker(select) {
  border: 1px solid #cbd5e1;
  border-radius: 0.75rem;
  box-shadow: 0 1rem 2rem rgb(15 23 42 / 18%);
}
Enter fullscreen mode Exit fullscreen mode

Style the open state

The :open pseudo-class can target the select while its picker is displayed.

select:open {
  border-color: #4f46e5;
  box-shadow: 0 0 0 3px rgb(79 70 229 / 20%);
}
Enter fullscreen mode Exit fullscreen mode

The picker icon also has a dedicated pseudo-element:

select::picker-icon {
  color: #64748b;
  transition: rotate 160ms ease;
}

select:open::picker-icon {
  rotate: 180deg;
}
Enter fullscreen mode Exit fullscreen mode

Remember to respect reduced-motion preferences if an animation is not essential.

Style options without losing their meaning

Options can receive richer visual treatment in supporting browsers.

option {
  padding: 0.75rem 1rem;
}

option:hover,
option:focus {
  background: #eef2ff;
}

option:checked {
  background: #e0e7ff;
  font-weight: 700;
}
Enter fullscreen mode Exit fullscreen mode

::checkmark can style the visual indicator for the selected option, while ::picker-icon targets the closed control's disclosure icon.

Selected content can be richer

The evolving customizable-select model permits a button as the first child of the select and introduces <selectedcontent> to display a clone of the chosen option's content.

<select name="plan">
  <button>
    <selectedcontent></selectedcontent>
  </button>

  <option value="starter">
    <span aria-hidden="true">🌱</span>
    Starter
  </option>

  <option value="growth">
    <span aria-hidden="true">🚀</span>
    Growth
  </option>
</select>
Enter fullscreen mode Exit fullscreen mode

Keep option labels concise and meaningful without their decorative icons.

Progressive enhancement is the safest rollout

Start with valid, ordinary select markup. Browsers without the new rendering path should retain a usable classic control.

@supports (appearance: base-select) {
  select,
  ::picker(select) {
    appearance: base-select;
  }

  /* Enhanced styling lives here. */
}
Enter fullscreen mode Exit fullscreen mode

Do not hide the select and replace it with an unsupported picker. The fallback is a feature, not a failure.

Framework and hydration risks

Modern parsing rules allow richer children inside a select, but some framework versions may still assume the older content model. Server-rendered markup can also differ from the client-side tree and cause hydration warnings.

Before adopting the richer markup:

  • test the exact framework and version
  • test server rendering and hydration
  • inspect the DOM produced in supporting and non-supporting browsers
  • keep a classic markup variant if your framework cannot preserve the structure

CSS-only enhancement of a normal select is a smaller first step than immediately using every new element and pseudo-element.

Accessibility testing remains necessary

Native semantics reduce risk, but visual customization can still create problems.

Check:

  • visible focus indication
  • keyboard selection and dismissal
  • high-contrast and forced-colors modes
  • zoom and text resizing
  • long labels and localization
  • disabled options and optgroups
  • screen-reader announcements
  • touch target size

Do not remove outlines without providing an equally strong focus indicator.

When to keep a custom component

A select is appropriate when a user chooses from a list of options. It is not automatically a replacement for every combobox, searchable command palette, tree picker, or multi-step menu.

If your interface needs asynchronous search, arbitrary text input, virtualized results, or complex option actions, a purpose-built component may still be necessary. Use the semantic pattern that matches the interaction.

A safe migration plan

  1. Choose one simple single-select field.
  2. Keep the current native markup.
  3. Add base-select styling inside @supports.
  4. Test all required browsers and assistive technologies.
  5. Introduce richer option content only after framework and hydration checks pass.
  6. Preserve the ordinary native control as the fallback.

Conclusion

Customizable select is exciting because it may finally reduce the trade-off between design control and native behaviour.

The best adoption strategy is incremental. Improve a real select where support exists, keep the classic control everywhere else, and let accessibility and compatibility tests—not a screenshot—decide whether the result is ready.

Sources:

Top comments (0)