YUI Button: Mimicking the native Select dropdown to avoid IE width problem

This is the 5th installment in YUI series. This installment uses YUI button widget and YUI keylistener utility. Although this post and example mimics the default SELECT element behaviour and look but you should also consider the JavaScript execution overhead this will cause.

Microsoft in all it’s glory continued to develop it’s own web standards, avoiding to support any open industry standards but then as technology progressed, word spread, people got knowledge and resources, open-source alternatives started to come into the market which now threatens the very existence of Microsoft itself. Yes, I am talking about the browsers at this moment, what Firefox and Google Chrome has done against a browser which comes pre-installed with an operating system which most of the people around the world use, yes the mighty IE (Internet Explorer).

As being a web-developer, you most probably would know the pain of working with IE. Although it has the developer tools now which makes the life a bit easier but what about it’s own implementation of DOM which is the only implementation and for this browser only,  a developer always feel forced to insert conditions in his/her code just so the code can work on IE as well. Anyway, this is something we all know about and can’t do anything until Microsoft thinks of something else. Let’s get to the business!

The problem with IE Select dropdown

IE Select dropdown width problem

If you are a web developer and you ever worked with a select dropdowns in your projects, you know this problem very well. IE by default don’t adjust it’s drop down panel according to the width of the longest text size. There are already work-arounds available and couple of them are based on YUI itself but they don’t mimick the exact look and feel of our old select dropdown list. I wanted the exact same look and  functionality of native SELECT element. I will list the work-arounds I founds:

Why a new fix?

Good question! The first fix I told you here, involves animation, when you get your mouse on the select element, it will animate itself to with of longest text option element, doesn’t look good to me as I think normal web user do not expect that to happen!

The second fix, had two major problems:

  • Scrollbars, my lists were very long as you will see in the example. By default YUI menu button’s scrollbars appear at the top and the bottom, if you increase the scroll rate for faster scroll, not very user friendly.
  • It didn’t had the important feature of selecting the options through keypress, I mean if you press B in normal select dropdown list, it will take you to the first item which is starting with B.

The fix itself!

Ok Ok, I think I am talking too much and few of my fellows will be in a hurry to get the code, copy paste it and get it done! Well, alright, the example is here:

Example: Work-around for fixed-width SELECT element

Explanation – The CSS

In fact I have modified the official YUI2 example.
First we need the same look as traditional select menu dropdown has. However if you want to make it more pretty, the CSS is here, do whatever you like to do, maybe using default arrow image of YUI is a better idea.

So, for the CSS, just as we override the default CSS rules of YUI skin sam:

.yui-skin-sam .yui-menu-button button {
    background-image: url("http://ciitronian.com/examples/images/select_arrow.PNG");
    outline: none;
    	font-size: 0.8em;
    	width: 15.2em;
    	background-color: #F8F8F8;
    	cursor: default;
    	line-height: 1.3em;
    	min-height: 1.45em;
	}
	.yui-skin-sam .yuimenuitemlabel:visited  {
	color:#000000;
	}

	.yui-skin-sam .yuimenuitemlabel  {
	color:#000000;
	cursor:default;
	padding:0 20px 0 0;
	text-decoration:none;
	}

	.yui-skin-sam .yuimenuitemlabel:hover  {
	background-color: #111166;
	color: #ffffff;
}

and a bit of tweak to YUI’s official example em class of button to make it look like a classic one

        /*  Restrict the width of the label to 10em. */
        width: 10em;

Our YUI menu button has got the classic look of SELECT element. Now the bit which I refer to as a nasty tweak, YUI menu button comes with it’s own scrollbars and as I mentioned earlier, if  you have a very long dropdown list, like a list of all countries in the world, the scrollbars functionality is not very useful. YUI gives you the flexibility to disable the scrollbars but I actually needed a vertical scrollbar so, what I did, I made the YUI scrollbars hidden!

Here’s what I did:

/*hide the YUI scroll bars*/
.yui-skin-sam .yuimenu .topscrollbar,
.yui-skin-sam .yuimenu .bottomscrollbar {
    height: 0px;
}

What it’s doing? Simply overriding the overriding the CSS property of height and setting it to 0. It hides the top and bottom scrollbars altogether. Next we need to turn the overflow to auto for yui menu body:

.yui-skin-sam .yuimenu .yui-menu-body-scrolled {
    overflow: auto;
    padding-right: 10px; /*to prevent horizontal scroll*/
}

If you just set overflow to auto, there will be just about a couple of pixels which will get over-flowed horizontally as well, to make it right, the padding property is there.  The padding-right property in div.yuimenu .bd is also there because IE8 was not getting right even if after the above rule.

Explanation – The JavaScript Code

The other JS code is almost the same as you will find in the official example but as mentioned earlier there were only two problems, the scrollbar, which we have already fixed through CSS, now the sorting or whatever you call it that when you click for a character, the first of it’s appearance should get selected automatically. So, all we need is basically a YUI keylistener with a correct scope and then we need to have a functionality which gets all the menu items text in an array, traverse the first character of each text element and then if matched, scroll to it and select it with the correct focus.

The keylistener code:

var kl = new YAHOO.util.KeyListener("select-1-container", { keys:keyArr },
			   { fn:labelCharCode,
				 scope:oMenuButton1,
				 correctScope:true } );
kl.enable();

The keylistener code select-1-container as first argument to give it correct scope. Notice the loops before this code in the source code of example, 65-90 are the keyboard character codes for A-Z characters and 48 to 57 are 0-9 characters. Next, keylistener calls the labelCharCode function with the keypressed event type, and arg[0] has the character which got pressed.

Now, the YUI Menu has a useful method of getting all items in a menu, as you see in the source code, I have used it to get the menu items:

var MenuItems = oMenuButton1.getMenu().getItems();

Now, in the labelCharCode, we have got the character which user has pressed, we need to match it with the first character of menu item. We access the text property of all menu items in a loop, slice the first character, match it in a if else block, if matched, simple old window.location takes us to the id of that menu item and then we fire the focus event for that menu item.

for (var i = 0; i < MenuItems.length; i++) {
			var firstChar = MenuItems[i].cfg.getProperty('text').slice(0,1);
			if(firstChar === Character){
				window.location = "#"+MenuItems[i].id;
				MenuItems[i].focus().fire;
				break;
			}

That’s it your SELECT dropdown element is ready which will work in all browsers and will adjust itself with the width of longest item in the menu!

Things which are still nagging me

The above code works as you may see in the example (I only tested that in IE8, Firefox 3.6 and Chrome 5), however I personally don’t like the concept of matching in a loop and slicing. I tried using YUI DataSource for this purpose but what I have seen in the YUI source code is that, it takes LocalDataSource array as it is and then apply matching on it, probably DataSource is more useful for remote data. However, I left it there after I tried seeing the code of AutoComplete widget and DataSource together, maybe I need to give it a bit more investigation. However, I dislike the current approach of this example because of processing involved. If you have a better understanding and know a better way of doing this, kindly embed the example or simply let me know, that will make this fix better!

Happy Coding!

Leave a comment

3 Comments.

  1. Can you please explain how to give the url behind dropdown values.

  2. I was facing the same problem :mad: in my website so i solved this bus on my own way…just check it out http://dropdownwidthproblem.blogspot.com/2011/07/i-was-on-google-round-clock-for.html

  3. Ruchi, your example is really not simple as the ppls commented on your blog..and it does not work on Firefox. for example.

Leave a Reply


[ Ctrl + Enter ]

Get Adobe Flash player