Simple Custom Select Box

by zerrax

HTML

<div>
    <label for="favouriteAnimal"></label>
    <select id="favouriteAnimal">
        <option value="">Select an option&hellip;</option>
        <option value="antelope">Antelope</option>
        <option value="dugong">Dugong</option>
        <option value="giraffe">Giraffe</option>
        <option value="koala">Koala</option>
        <option value="turkey">Turkey</option>
        <option value="wombat">Wombat</option>
    </select>
</div>

CSS

body {
    padding: 50px;
}
body > div {
    display: inline-block;
    margin-bottom: 20px;
    margin-right: 20px;
}
label {
    color: #444;
    display: inline-block;
    font: bold 16px/1.5 sans-serif;
}
label:after {
    content: ':';
}
.hidden {
    visibility: hidden;
}
.select {
    cursor: pointer;
    display: inline-block;
    padding-right: 16px;
    position: relative;
    -webkit-user-select:none;
       -moz-user-select:none;
        -ms-user-select:none;
         -o-user-select:none;
            user-select:none;
}
.styledSelect {
    background-color: #ddd;
    background-image: url('http://cdn3.iconfinder.com/data/icons/fatcow/16x16_0140/bullet_arrow_down.png'),
                      -webkit-linear-gradient(hsla(0,0%,100%,.1), hsla(0,0%,0%,.1));
    background-image: url('http://cdn3.iconfinder.com/data/icons/fatcow/16x16_0140/bullet_arrow_down.png'),
                         -moz-linear-gradient(hsla(0,0%,100%,.1), hsla(0,0%,0%,.1));
    background-image: url('http://cdn3.iconfinder.com/data/icons/fatcow/16x16_0140/bullet_arrow_down.png'),
                          -ms-linear-gradient(hsla(0,0%,100%,.1), hsla(0,0%,0%,.1));
    background-image: url('http://cdn3.iconfinder.com/data/icons/fatcow/16x16_0140/bullet_arrow_down.png'),
                           -o-linear-gradient(hsla(0,0%,100%,.1), hsla(0,0%,0%,.1));
    background-image: url('http://cdn3.iconfinder.com/data/icons/fatcow/16x16_0140/bullet_arrow_down.png'),
                              linear-gradient(hsla(0,0%,100%,.1), hsla(0,0%,0%,.1));
    background-position: 97% 60%;
    background-repeat: no-repeat;
    border-radius: 3px;
    bottom: 0;
    box-shadow: 0 1px 4px hsla(0,0%,0%,.25),
                inset 0 0 0 1px hsla(0,0%,0%,.25),
                inset 0 0 0 2px hsla(0,0%,100%,.25);
    color: #fff;
    font: 14px/24px sans-serif;
    left: 0;
    padding: 5px 15px;
    position: absolute;
    right: 0;
    text-shadow: 0 1px 1px hsla(0,0%,100%,.5);
    top: 0;
   ...

JavaScript

var numberOfSelects = $('select').length;

// Iterate over each select element
$('select').each( function() {
    
    // Cache the number of options
    var $this = $(this),
        numberOfOptions = $(this).children('option').length;
    
    // Hides the select element
    $this.addClass('hidden');
    
    // Wrap the select element in a div
    $this.wrap('<div class="select" />');
    
    // Insert a styled div to sit over the top of the hidden select element
    $this.after('<div class="styledSelect"></div>');
    
    // Cache the styled div
    var $styledSelect = $this.next('div.styledSelect');
    
    // Show the first select option in the styled div
    $styledSelect.text($this.children('option').eq(0).text());
    
    // Insert an unordered list after the styled div and also cache the list
    var $list = $('<ul />', {
        'class' : 'options'
    }).insertAfter($styledSelect);
    
    // Insert a list item into the unordered list for each select option
    for(var i = 0; i < numberOfOptions; i++) {
        $('<li />', {
            text: $this.children('option').eq(i).text()
        }).appendTo($list);
    }
    
    // Cache the list items
    var $listItems = $list.children('li');
    
    // Show the unordered list when the styled div is clicked (also hides it if the div is clicked again)
    $styledSelect.click( function(e) {
        e.stopPropagation();
        $('div.styledSelect.active').each( function() {
            $(this).removeClass('active')
                .next('ul.options').filter(':not(:animated)').slideUp(250);   
        });
        /* Use this instead of the .each() method when dealing with a large number of elements:
        for(var i = 0; i < numberOfSelects; i++) {
            if($('div.styledSelect').eq(i).hasClass('active') === true) {
                $('div.styledSelect').eq(i).removeClass('active')
                    .next('ul.options').filter(':not(:animated)').slideUp(250);
            }
        } */
       ...