Form elements have always been a problem for designers, they are ugly as fuck and never match a website or app style. In an earlier age javascript plugins popped up to solve this problem, at the expense of creating new problems. First let me make a case about not using js in this situation and then I will show you how you can very effectively style form elements with css while progressively enhancing & using the default style for older browsers like ie7.

You can skip ahead to the form element styling if you don’t want the rant about not using javascript.

Why not replacing native implementation by your own with javascript

The behaviour

Making a javascript plugin that make a select element behave exactly like the native one is already hard (keyboard support, no js & etc), but even then you need to ask, which default browser behaviour you want to replicate, Chrome? Internet explorer?

Browsers implement more & more utilities for their users (and yours), for example, password inputs now have a show text icon on IE10. When you replace form elements with javascript you become at odd in the future with the behaviour the user is expecting to find using a form in your app because default behaviors changes with browser versions.

The bugs

Even Choosen which is one of the oldest (and arguably one of the best) plugin to style Select element has currently 150 issues in their bugs tracker. The native implementation has zero bugs & always works as expected by the user whatever the browser he is using.

The sometimes weird loading page state

Most JS plugins are built to show default form elements when javascript is disabled, which unfortunately can create some weird loading effect. Sometimes, for a split second you can see those elements or/& the content move a bit like a hidden margin was disappearing.

The code bloat

These scripts are often short of small, this add loads on your app, + you must handle these plugins state, that means more code & more bugs & longer implementation.

& then the ugly

You know that div with a scroll overflow that replace your select options box, well what happen when you scroll at the end of it? You start scrolling the page. When using a normal select box, when you reach the end it just stop scrolling, like it should.

I’m sure you picked that up sometimes, personally I first picked that up using the website to buy a house, the city I was looking for was at the very end of the select box, every time I would scroll that page looking for that city, and that’s certainly annoying after a couple of times.

Want a better select box create a better element not a “better” select box

You want a search element within your select box? The answer does not lie with a javascript select box. Create a better UI element that will actually better complement your form.

Adding a search box is generally flawed from the get go. You make the assumption the user know what to search when most of the time they have no idea what lies behind the border of your scroll overflowed div, how can they search?

You also make the assumption that users want to actually switch from using the mouse to scroll. You completely break the flow, the user now has to click on the search box and then change their focus to the keyboard, and eye back and forth the keyboard to search something.

Maybe this thread on UX stackoverflow can help you make a better choice with this.

Styling form elements

So we got the arguments out of the way let’s concentrate on the technique we can use to style those damn elements. If you just want the example with the css, click here.

The select

Obviously we can’t style the option box, but we can style pretty effectively the select shown in your web page. This basically involves wrapping our select in a div and style that div instead of styling the select element. The right arrow is a bit of the problem, it will be shown on some browsers, and we also need to degrade to normal select box on ie7.

It is fully supported on Chrome, IE10, firefox chrome, partial support with normal arrow on IE8, IE9 & firefox PC.


Here the basics:

    <div class="selectContainerStyled">
        <div class="arrow"&gt;</div>
            <option value="Option 1">Option 1</option>
.selectContainerStyled {
  position: relative;
  border: 1px solid #b5b5b5;
  border-radius: 4px;
  background-clip: padding-box;
  background-color: #f1f1f1;
  box-shadow: 0 1px 3px rgba(0,0,0,.13), inset 0 1px 0 #fff;
  color: 0 1px 3px rgba(0,0,0,.13), inset 0 1px 0 #fff;
  background-image: linear-gradient(bottom, #dcdcdc 0%, #dcdcdc 2%, #f3f3f3 100%);
.selectContainerStyled select {
  float: left;
  position: relative;
  z-index: 2;
  height: 30px;
  display: block;
  line-height: 14px;
  padding: 5px 25px 4px 5px;
  margin: 0;
  -moz-appearance: window;
  -moz-padding-end: 19px;
  background: transparent;
  background-color: transparent;
  border: none;
  -webkit-appearance: none;
  appearance: none;

Radio & checkbox

This time the idea is to add a div after the form element, put it below the element & hide the form element. Using a small css3 trick we change the div state with a small selector.

It is fully supported on Chrome, IE9+, firefox.


Here the basics:

<input checked="checked" type="radio" name="action" value="0" id="nocategory" class="radioChanged">
<div class="radioContainer"></div>
input:checked + .checkboxContainer{
  background-position:top right;


In the end you don’t need javascript to make form elements pretty, the only exception would be working on a website clie here the client stubbornly wants all elements always looking the same even if that means loosing some usability. it’s your job to explain the consequences a technology you use has on the whole project, but if that still not enough, use some JS alternative, at least you tried.

As noted in the comments I need to add :focus selector to add an outline when tabbing with the keyboard through the form, thanks guys!

5 thoughts on “How to style select, radio & checkbox form elements only with css

    1. To further clean up the HTML, lose the empty .arrow DIV and use the :before pseudo-element instead.

Comments are closed.