Custom React Dropdown With Native Mobile Behavior

Customize your <select> elements without reinventing the wheel

Mateusz Hadryś
4 min readFeb 15, 2019

This post is for you if you’ve ever asked yourself one of these questions:

  • How to open the select dropdown menu programmatically
  • How to style the select element?
  • How to make a custom element preserve native <select> tag behavior?
  • How to use custom icons with the select element?

What?

I will show you how to make any element into a select with native behavior but completely custom styling and contents.

Why?

The select element is notoriously hard to style, especially in a way that works across browsers. If you also want to include custom elements inside, like icons, it becomes even harder.

Custom select menu made using this method

You could implement your own select element with custom logic, but for most applications that’s unnecessarily complex. Dropdown menus don’t work very well on mobile devices, which is why mobile browsers render them as fullscreen overlays. This adds additional complexity to any custom component implementation, as you need to handle two different display modes.

Simply using a label or dispatching events like: click, keydown, change doesn’t work. It will only focus the element. (dispatching the click event might work in Chrome, but this method should not be used anyway, as it is considered deprecated in Chrome 53+). It turns out that triggering the select dropdown programmatically is impossible. So what now?

How?

  • Create a container with a select and label inside it (It is important to put the label after the select, I’ll explain why in a second)
  • Give the container position: relative and define its dimensions
  • Give the select position: absolute and stretch it out to cover the entire container by setting width:100%; height:100%; top:0; left:0;
  • Hide the select by giving it opacity: 0
  • Using this selector selector:focus + label you can style the focused state, this is also why the label has to come after the select

This way we are able to display anything we want as the clickable component and still keep the native behavior. Do you want to show an animated loader to indicate options being loaded from the server? Done. Do you want to use a third party icon library? Done. Do you want to use your own SVGs? Also done.

If you want to change the content or appearance of your component, based on which option is selected, just turn it into a controlled component and modify the children based on the state.

Here is the code, feel free to play around with it:

Accessibility

The select tag is technically still there so you can still focus it with your keyboard and with some clever CSS you are also able to style the :focus or :hover state. Wrapping the custom element in the label tag should aid screen-readers in knowing what the select is for.

Alternatives

  • If you need full control and are ready to take on the complexity, you should probably implement your own Select component from the ground up.
  • If you only want to change the dropdown icon and you don’t mind using an image, you could try using the background-image method. Check out this example:

If this guide helped you consider leaving a few claps 👏 If something was unclear, or you would like me to expand on some topic, let me know in the comments 💬 All constructive criticism is welcome.

--

--

Mateusz Hadryś

I write about web development tips & news. Follow me on twitter for more: twitter.com/HadrysMateusz