Monthly Archives: May 2015

Styling a select box with CSS and jQuery

As mentioned on Twitter last week, HTML form elements and style are a pain in the ass. Some things a customer wants are not possible with HTML and CSS only, some can be improved with JavaScript. Last problem on a customer project I had were select elements with size="1" or a dropdown menu as a UI designer would probably call it. Note right here: yes it has to be <select> because it’s inside a form which should work without JavaScript as well.

I personally liked the approach of formalize.me very much, not designing all by myself but just tweak it to reasonable consistent looking. This was not an option in this case. I reviewed some solutions with CSS only but they all had drawbacks or visible flaws. Already using jQuery in this project jQuery UI came to my mind, but making a complete new style to match the requirements or extracting just the needed parts from selectmenu seemed to complicated.

A solution I liked was the one by Ryan Fait on Checkboxes, Radio Buttons, Drop Down Menu Select Lists, Custom Form Elements, CSS Form Styling. On the first look it seems to be fully integrated in your style, only after clicking on the select menu you get the browser/operation system UI elements, which is a good compromise with less complexity. Because I already had CSS only solutions for check boxes an radio buttons I only needed the select list part.

Ryan uses plain JavaScript and I thought I could simplify the code, because I use jQuery in this project anyway, so this is my solution.

HTML with some options left out for brevity:

<div id='timezone'>
  <label for='select_tz' class='before like_dl_dt'>Time Zone</label>
  <select size='1' name='lst_zone' id='select_tz' class='select_like_dl_dd'>
    <optgroup label='America'>
      <option value='America/Sao_Paulo'>Sao_Paulo</option>
      <option value='America/Puerto_Rico'>Puerto_Rico</option>
      <option value='America/Caracas'>Caracas</option>
    </optgroup>
    <optgroup label='Europe'>
      <option value='Europe/Berlin'>Berlin</option>
      <option value='Europe/Oslo'>Oslo</option>
      <option value='Europe/Copenhagen' selected='selected'>Copenhagen</option>
    </optgroup>
  </select>
</div>

CSS:

.like_dl_dt {
	width:		150px;
	margin:		4px 0 0 16px;
	display:	block;
	float:		left;
}

.select_like_dl_dd {
	width:		170px;
	height:		20px;
	margin:		0 0 6px 166px;
	z-index:	5;
	display:	block;
}

.select_face {
	position:	absolute;
	overflow:	hidden;
	line-height:	20px;
	background:	rgb(237,239,242) url("select_bg.png") no-repeat;
	border:		1px solid rgb(208,212,215);
	border-radius:	3px;
	height:		20px;
	padding:	0 4px;
	width:		160px;
}

The select_bg.png file for this case is 168×20px. JavaScript with jQuery already loaded:

$(document).ready(function(){
	var span = $("<span></span>")
			.attr("class", "select_face")
			.attr("id", "select_tz_face")
			.text($("#select_tz").val().split('/').pop() );
	$("#select_tz")
			.css("opacity", "0")
			.before( span );
	$("#select_tz").change(function(){
		$("#select_tz_face").text( this.value.split('/').pop() );
	});
});

Note: the value/split stuff is because the value of the <option> elements is different from the content, but on select box change I do not want to display the actual content. I’m not sure if one can access the text between the option tags, if yes, sent me a hint! ;-)

You see I left out a lot here and there’s no easy to inspect example for download, but I’m sure you can puzzle it together by yourself. :-)

Update: after a hint in the comments I came up with a better solution for the Update of the face span, see:

	var span = $("<span></span>")
			.attr("class", "select_face")
			.attr("id", "select_tz_face")
			.text( $(":selected").text() );
	$("#select_tz")
			.css("opacity", "0")
			.before( span );
	$("#select_tz").change(function(){
		$("#select_tz_face").text( $(":selected").text() );
	});

:-)