posted on:September 7, 2010

Custom styling of the SELECT elements


Recently I have been asked by my client to some custom styling on form elements. As you know we have no issues (well, at least no major issues) when it comes to prettifying input fields, text areas and buttons. But the form I needed to apply custom design to contained couple of select elements. Now this is something that’s not that simple.

I always aim for the simplest solutions possible in everything I do, not just work related. I enjoy having short, few lines scripts, reduced markup etc. That is why I didn’t opt for some of the ready made solutions we have out there. I rather tried to come up with the solution of my own.

Custom styling for select elements

Take a look at the demo or
Download files

How it works

The solution I am talking about here is actually a workaround, trick. It works in a way that it dynamically adds an additional SPAN element positioned absolutely below the SELECT element. This SPAN has a custom graphic that we want to apply. SELECT element’s opacity is set to zero so it is not visible but it’s clickable. Since the SELECT element is not visible, what we see actually is the SPAN below.

This solution doesn’t style the OPTION dropdown, only the default appearance of the SELECT element but considering the simplicity I (and my clients 🙂 ) believe that it is very applicable.

Important thing to remember: this trick relies heavily on absolute positioning. Newly created SPAN element will position itself in relation to parent element (DIV in my case). If you have other stuff inside the parent element, things like text, labels etc. make sure that you position the newly created SPAN accordingly.

Also, as with any other project I am working on, I used jQuery as the library of choice.

The script

Here is the entire script:

$(document).ready(function(){	

    if (!$.browser.opera) {

        $('select.select').each(function(){
            var title = $(this).attr('title');
            if( $('option:selected', this).val() != ''  ) title = $('option:selected',this).text();
            $(this)
                .css({'z-index':10,'opacity':0,'-khtml-appearance':'none'})
                .after('<span class="select">' + title + '</span>')
                .change(function(){
                    val = $('option:selected',this).text();
                    $(this).next().text(val);
                    })
        });

    };
		
});

Script, line by line explained:

$(document).ready(function(){

Script executes on DOM load.

if (!$.browser.opera) {

Had some issues with transparency in Opera so I decided not to support Opera for this trick.

$('select.select').each(function(){

What follows will apply to every SELECT element with the class name select

var title = $(this).attr('title');

Each SELECT element should have TITLE attribute set to whatever we want to show as a default value of the drop down. We are storing the value of the TITLE attribute in a variable for further usage.

if( $('option:selected', this).val() != ''  ) title = $('option:selected',this).text();

Checking if any of the options is selected by default. If it is we will use it as a default value. If not, we are using the previously stored TITLE attribute value.

$(this)
	.css({'z-index':10,'opacity':0,'-khtml-appearance':'none'})

For each of the SELECT elements we are setting the z-index to anything above the value of 1, opacity to zero, and we’re also removing the default styling for Safari.

	.after('<span class="select">' + title + '</span>')

We are then adding a SPAN element that have background image set in CSS and is placed exactly below the SELECT element.

	.change(function(){
    	val = $('option:selected',this).text();
    	$(this).next().text(val);
    	})

With every change of value for the SELECT elements we are updating the SPAN element inner text.

HTML/CSS source code

Just as a script, proper markup and CSS is very important to make this to work. SELECT elements needs to be wrapped inside a parent element (DIV in my case) that has a position property set to relative, so the newly created SPAN can be properly positioned.

This is the markup for the SELECT element:

<div>
<select class="select" title="Select one">
    <option></option>
    <option>Blue</option>
    <option>Red</option>
    <option>Green</option>
    <option>Yellow</option>
    <option>Brown</option>
</select>
</div>

Note the TITLE attribute. Script will use it as a defautl value.

CSS looks like this (some comments included):

/* all form DIVs have position property set to relative so we can easily position newly created SPAN */
form div{position:relative;} 

/* setting the width and height of the SELECT element to match the replacing graphics */
select.select{
    position:relative;
    z-index:10;
    width:166px !important;
    height:26px !important;
    line-height:26px;
}

/* dynamically created SPAN, placed below the SELECT */
span.select{
    position:absolute;
    bottom:0;
    float:left;
    left:0;
    width:166px;
    height:26px;
    line-height:26px;
    text-indent:10px;
    background:url(images/bg_select.gif) no-repeat 0 0;
    cursor:default;
    z-index:1;
	}

Try the demo, download the files and of course let me know what you think 🙂

Enjoyed the article?

Then don't miss our next one! Subscribe to our RSS feed or share it with your friends.

DeliciousStumbleUpon RedditSubscribe

Comments (27 Comments)

  1. Thomas Svensson
    September 7, 2010

    Nice! And browser support?
  2. Mladen Stepanic
    September 7, 2010

    I wrote a sorta plugin for the same thing, just this one supports styling of option lists, and optgroups. The code itself is still in very dirty phase (you may consider this a draft), but I'll clean it up once I get enough free time (and also implement custom scrollbars). In the meantime you can look at it at: http://emforma.rs/temp/t14/index2.html
  3. Pippin
    September 7, 2010

    This is awesome, though anyone who uses this should also style all elements accordingly for browsers with JavaScript disabled.
  4. cssglobe
    September 7, 2010

    I tested it in FF, Safari, Chrome and IE8. Opera had issues so I don't support it at all. For non JS clients everything will remain as is, no styling applied.
  5. Davor
    September 7, 2010

    Very nice, the biggest issue I found using this kind of methods is limited select width in IE family and long select options. Using "width:auto" for IE-only generally helps
  6. IGotNothin
    September 7, 2010

    Bummer no Opera support, that's my preferred browser and typically not a problem to program for. I also get an Out of Memory error when viewing the demo page in IE 8.
  7. Matt
    September 8, 2010

    These look good, but there are a few irritating issues. There's a really nasty flash of the original, unstyled elements in chrome on mac. Also, the width of the popup list is much smaller than the custom select element, and it is always aligned way to the left. So, if I click the down arrow on the right, I have a long way to move my mouse to get to the options.
  8. Carlos
    September 8, 2010

    Nice way to style this, but we're kinda far from style forms properly... I've made a hard choice doin' this: http://www.bhshopping.com.br/ look at the "select in "BUSCAR POR LOJA" it would be nice if the form elements were that easy to style...
  9. Mike
    September 10, 2010

    Love the simplicity. Now can you show me a simple version to style checkboxes? :)
  10. Wael Al-Sallami
    September 12, 2010

    Would've loved it more if it had hover and active states and I know they're easy to implement using jQuery ... just a thought ;)
  11. ANdReiâ„¢
    September 12, 2010

    Normal selects also have type in support, which causes these custom selects some head aches. I don't think it's hard to fix though :)
  12. Mathias
    September 12, 2010

    Or just use <a href="http://pixelmatrixdesign.com/uniform/">Uniform (sexy forms with jQuery)</a>…
  13. Diti
    September 12, 2010

    The form is absolutely unusable (ergonomic) when navigating with keyboard, since it doesn’t show where your “tabulation” is, if you understand what I mean.
  14. Jonathan
    September 12, 2010

    @Diti It wouldn't be considered a "work-around" if it was perfect. This script is really cool, although the initial flash reminds me of the @font-face text flash. I'd definitely use this if it got rid of that flash.
  15. Ricardo
    September 13, 2010

    We use a similar trick at our company, but instead of absolute positioning we wrap the select in a div with position:relative and a span inside, then the select is positioned to overlay it's parent. We also listen for the keydown event and set focus styles for accessibility.
  16. XingWoo
    September 13, 2010

    Oh wow, thats prtty cool dude. www.real-anonymity.es.tc
  17. Thany
    September 13, 2010

    I understand you had issues with opera... Insurmountable issues? Or did you simply not have enough time to solve them?
  18. Volomike
    September 13, 2010

    Pretty, yes, but highly recommend that it be responsive to tab key and arrows and use a visible outline -- for the accessibility needs type of customer.
  19. Ritu
    September 14, 2010

    I think digit is best for shopping electronic items.
  20. cmacias
    September 19, 2010

    without jquery, for all (except ie6) ;) http://www.cmacias.com/cambiando-el-aspecto-de-los-selectbox/ or http://www.cmacias.com/mejorando-los-selectbox/ or multiple http://www.cmacias.com/selectbox-multiple/ And how to change the input type file part 1. http://www.cmacias.com/maquillar-un-input-file-upload/ and part 2 http://www.cmacias.com/maquillar-un-file-upload-2/
  21. Beben
    September 22, 2010

    full stylish...i like it :-bd
  22. Ben Stokes
    September 25, 2010

    Nice work guys and nice clean code - enjoyed this very much :)
  23. algerien-dev
    September 26, 2010

    Hi, nice. http://www.filamentgroup.com/lab/jquery_ui_selectmenu_an_aria_accessible_plugin_for_styling_a_html_select/ is pretty nice too 0_^
  24. Antti202
    September 29, 2010

    Great article, it was very easy to implement it ;)
  25. tildy
    September 30, 2010

    Sometimes the jquery codes are not working perfectly, if you use a protoype.js too. Otherwise, why can't I use on Opera ( Ok , I can see in the code , that Opera is "not supported" , but why?
  26. Web Designer Leicester
    September 30, 2010

    Thanks for sharing, this is really useful. Select elements have always been a bit of a mystery to me when styling.
  27. David Christian-Woodruff
    October 6, 2010

    Thanks for this! It's not always the first thing that people think about when designing a web page, or indeed even if they do, and so having something that enables them to style Select elements is an excellent addition to the process. What's more is that it certainly makes a page look more clean and professional, something that clients will pick up on when viewing a design for the first time.

Sorry, the comment form is closed at this time.