Styling any form element with CSS is a pain in the ass, but select fields probably take the cake for being the absolute worst. CSS-Tricks provides some basic information on how to style a dropdown without any hacks, but that will not get you very far, especially since the actual dropdown menu is off limits. Moreover, cross browser support for things like appearance to hide the dropdown arrow are spotty at best. If you have to support IE9 or below then you will have to get creative and hide the dropdown with overflow: hidden.

So what are you supposed to do if you really want a customized select input? The answer is not pretty, you have to build a select box from scratch. Thankfully there are numerous resources for this; Bootstrap, for example, has a button dropdown that can be coopted for your custom select input and plugins like SelectBoxIt can easily transform any select input into a feature rich version.

Unfortunately, however, there are currently no plugins that support a key feature on iOS devices, the picker. The picker should be the preferred input method over dropdowns for several reasons: its the standard method across iOS devices and its easier to use than most dropdowns thanks to its increased font size and its ability to scroll.

The lack of support is not surprising, however, since the only way to open up the picker in Safari is to press on an actual select element, the element you inevitably get rid of when you build your select from scratch.

Giving Focus to a Hidden Select

The trick is to not get rid of the select box entirely. By keeping it on the page, we can give it focus when the user clicks on the select box, thereby opening up the picker. You may want to try programmatically applying focus to the input whenever the select box is clicked, but this strangely does not work (there is apparently a work around for Chrome as mentioned by Xavier Ho). Most likely this is a security feature.

This means that the user literally has to click the select button in order for this to work. At this point you have two options. Either you can place a nearly invisible select field on top of your custom button (inputs with opacity:0 cannot receive focus) or place the select field underneath the button and turn off events for the button with pointer-events. I’ll show you both.

Thankfully they use the same markup, which I have below.

<div id="select" class="dropdown">
  <select>
    ...
  </select>
  <button id="dLabel" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" class="btn btn-primary">
    <span class="value">Select Pet</span>
    <span class="caret"></span>
  </button>
  <ul class="dropdown-menu" aria-labelledby="dLabel">
    ...
  </ul>
</div>

Creating a nearly invisible input is perhaps the easiest method. All you need to do is layer the select above your button and set the opacity to something ridiculously small, say 0.001. I originally found this solution on Stack Overflow by macinjosh, and as long as you keep the select input before the button in the DOM, you can add a hover style to the button by using the + operator.

.dropdown {
  display:inline-block;
}
select {
  position:absolute;
  -webkit-appearance: menulist-button;
  width:100%;
  height:100%;
  opacity:0.001;
  z-index:100;
}

.btn-primary {
  position:relative;
}

select:hover + .btn-primary, .btn-primary:hover {
    background-color: darken(#ca12ea,5%);
    border:5px solid darken(#ca12ea,25%);
}

See the Pen Opacity Hack by Matthew Bolanos (@matthewbolanos) on CodePen.

You might be tempted to add the hover styles by applying them based on the hover state of the parent element, in our case the div with id=“dropdown”, but this will introduce complications when we start working with our actual dropdown menu.

The other option, as mentioned previously is to layer the select below the button and simply turn off pointer-events for the dropdown button. I personally prefer this method because it avoids having to use the z-index property and I find the opacity trick hackier than I would like.

.dropdown {
  display:inline-block;
}
select {
  position:absolute;
  -webkit-appearance: menulist-button;
  width:100%;
  height:100%;
}

.btn-primary {
  position:relative;
  pointer-events:none;
}

select:hover + .btn-primary, .btn-primary:hover {
    background-color: darken(#ca12ea,5%);
    border:5px solid darken(#ca12ea,25%);
}

See the Pen Pointer-events Hack by Matthew Bolanos (@matthewbolanos) on CodePen.

Either option works, but for the remainder of the tutorial I will use the second method.

Giving Focus to the Dropdown Button

At this point, if we were just designing a page for iOS, we would be done; we have a custom button that opens up the iOS picker. Our problem, however, is that we no longer have a custom dropdown on Android or on desktop.

Thankfully opening up the dropdown is relatively easy to solve. Simply add an event listener for when the select gains focus, check if the device is not iOS (hacky I know, but this whole tutorial is a hack), hide the actual select input to prevent the dropdown from showing up, give focus to the dropdown button, and toggle the dropdown.

var iOS = /iPad|iPhone|iPod/.test(navigator.platform);

$("select").focus(function() {
  if (!iOS) {
    var $select = $(this);
    var $button = $('button');

    $select.hide();
    $button.focus();
    $button.dropdown('toggle');
  }
});

The reason I purposefully hid the select input instead of just changing focus is that most browsers prevent you from changing focus once the select is open. By simply getting rid of the select element, the problem goes away.

To bring the select box back you can use a timeout, but if the user’s click is longer than the timeout it won’t work, so I decided to just attach it to the button’s blur event.

$("button").blur(function() {
  var $button = $(this);
  var $select = $('select');
  $select.show();
});

The last thing you want to do is set the select’s value whenever the user clicks on the dropdown. This part is optional, but you probably want to do it if you ever plan on submitting your form, and it is easy enough with a few lines of jQuery.

$("li a").click(function() {
  $("select").val($(this).html());
  $(".value").html($(this).html());
});

And that is it! After all of that hard work you finally have yourself a dropdown that does not suck on iOS. Congrats. Below is the final product.

See the Pen Adaptive Custom Select Button by Matthew Bolanos (@matthewbolanos) on CodePen.