Select, Option, Disabled And The JavaScript Solution

As I mentioned recently, there is a bug in Internet Explorer that stops you from disabling options in a select/dropdown element. At the time, I felt this was quite poor so I set about finding a solution. For the impatient among us, you can step straight to implementing it if you want.

Unsuccessful Ideas

In an attempt to save everyone else some time, I’m going to list the different ideas, methods and combinations of, I attempted that were unsuccessful:

  1. Attempt: use the CSS pseudo :hover against the <option> element.
    Problem: Internet Explorer doesn’t support the :hover pseudo class on arbitrary elements.
  2. Attempt: Wrap the contents of the <option> element in an anchor and use the :hover on that instead.
    Problem: The <select> tag is considered a replaced element, which means the tag is replaced with your operating systems equivalent. As a by product, no other HTML element is valid within the <option> tag.
  3. Attempt: Use the JavaScript onmouseover and onmouseout events on the <option> element to make the element appear as though it was disabled.
    Problem: Internet Explorer doesn’t support the onmouseover and onmouseout events against an <option> element.
  4. Attempt: Use the JavaScript onclick event on the <option> element to check if the disabled attribute has been applied, act accordingly if it has been.
    Problem: Again, Internet Explorer doesn’t support the onclick event againt the <option> element.
  5. Attempt: Use the JavaScript onclick event against the <select> element, to again check if an <option> has the disabled attribute in use.
    Problem: Internet Explorer doesn’t support the onclick event against a <select> element.

Successful Ideas

The solution to this problem is comprised of two parts. Firstly, knowing when you make a selection or change the current selection. Secondly, keeping track of the current selection, so you can revert to it in case the user selects a disabled option in the list. If those two things can be achived, then we can emulate the disabled attribute on an option element

Part 1
You can get around not having an onclick event against the option element by using an onchange event against the select. Knowing when you click an option is mandatory, as it lets you know when/if to check that the selected option is disabled. This is taken care of, we can move on.

Part 2
Next up is keeping track of the ‘currently selected’ item. Generally, the first tool in the chest that most people reach for in this case is an onclick event. However, since we’re working with a browser that doesn’t implement those events on the element(s) in question, another solution was needed. The next event that would match what we want to do is onselect, however it isn’t implemented in IE either. Thankfully, the onfocus event is our savior.

How It Works

First thing is making sure that the code only executes on the correct browsers. You could use browser sniffing techniques or proprietary JavaScript functions to isolate IE, however that can be inconsistent. Since we’re targeting IE, it seems more than reasonable to use a conditional comment. In case you are unfamiliar with them, a conditional comment looks like a standard HTML comment to every non-IE browser; however IE interprets them and allows the author very simple conditional testing. We’re going to use this simple testing to include an external JavaScript file.

If the JavaScript does execute, it checks to see if you have any <select> elements in the page. If you do, it iterates through them, attaching an onchange and an onfocus event to each one. At the same time, the disabled option elements (if there are any) are also highlighted with the disabled text colour.

At this point, you have nothing else to do. The onload event and the two functions will do everything for you from this point. The one caveat is if you are manipulating the disabled attributes on the options through the DOM. In which case, you do have to call the emulate function, passing into it a reference the <select> you are manipulating.

The JavaScript

To make this work, an event and two functions are used. They are listed here so you can glance over them:

  1. window.onload = function() {
  2. if (document.getElementsByTagName) {
  3. var s = document.getElementsByTagName("select");
  4. if (s.length > 0) {
  5. window.select_current = new Array();
  6. for (var i=0, select; select = s[i]; i++) {
  7. select.onfocus = function(){ window.select_current[this.id] = this.selectedIndex; }
  8. select.onchange = function(){ restore(this); }
  9. emulate(select);
  10. }
  11. }
  12. }
  13. }

The restore function returns the selected item to its previous selection, if the newly selected item is disabled.

  1. function restore(e) {
  2. if (e.options[e.selectedIndex].disabled) {
  3. e.selectedIndex = window.select_current[e.id];
  4. }
  5. }

The emulate function changes the font colour of all options in a <select> element with the disabled attribute set. The colours used on lines 4 and 7 are CSS2 colour names, which are considered system colours. System colours reflect what your current computer settings are, so they should change with your current desktop theme (at least that is my interpretation of it).

  1. function emulate(e) {
  2. for (var i=0, option; option = e.options[i]; i++) {
  3. if (option.disabled) {
  4. option.style.color = "graytext";
  5. }
  6. else {
  7. option.style.color = "menutext";
  8. }
  9. }
  10. }

Implementing

Using this script is meant to be as simple as possible. All you have to do is download the external JavaScript file. Upload it to your site and place a single conditional comment in your HTML, such as:

  1. <!--[if lt IE 7]>
  2. <script type="text/javascript" src="select-option-disabled-emulation.js"></script>
  3. <![endif]-->

Examples

Following are some simple examples to display what Internet Explorer renders at the moment, through either html/xhtml/quirk/compliant states. There are also two examples of how the script functions as well, simple but they demonstrate it none the less.

Follow Up

After this post being active for over a year now, it continues to draw in consistent traffic from around the internet. Even though this was a proof of concept and not a complete solution, it has saved many people a lot of time. Plenty of people have taken the basic idea I started with and extended it, which I think is fantastic. Recently, a couple of people have sent through comprehensive techniques which are either built on my initial work in some way or inspired by it. These solutions are out perform my simple proof of concept, so they are definitely worth noting for everyone to use:

  • Apptaro created an elegant solution using a DHTML Behaviour file. These behaviour files only execute in Internet Explorer which is a great way isolating it from interfering with other web browsers.
  • Kaleb Walton has implemented a JavaScript object oriented version of my proof of concept. Kaleb’s version implements the fix for a standard dropdown, a listbox and a multi-select listbox.

Both of the above examples are excellent, so you should pick which ever you feel is best going to suit your needs.

59 thoughts on “Select, Option, Disabled And The JavaScript Solution

  1. As I said, IE doesn’t implement the disabled attribute on option elements. This was something to try and improve that situation through JavaScript. Clearly, if they disable JavaScript, they don’t get the benefits – they are however, no worst off though.

    Al.

  2. Do you think you could use Behavior files to implement this too? From what I understand, behaviors are an IE-only feature, so it might work just as easily as the conditional comments. I looked everywhere to see if there was already a behavior file out there that would fix something like this, but no luck. There are lots of PNG fixes using behavior files though, so I’m sure it wouldn’t be impossible.

    More info about Behavior files: http://msdn.microsoft.com/workshop/author/behaviors/howto/creating.asp

    Thanks!

  3. I just received an email from the author. I find it quite ironic that on nearly every post about javascript, some lurker comes by and posts something like ‘what if they disable javascript?’

    Cheers to your blog, and thanks for the email :)

  4. Just som time ago i was challenged with the same problem. So i made a small script. Hope it helps you all out there.
    Just bind it in your onchange event of your select element: –> li_selIndex)
    {
    li_selIndex-=1;
    }
    else
    {
    li_selIndex+=1;

    }

    if(po_object.options[li_selIndex])
    {
    po_object.selectedIndex=li_selIndex;
    }
    else
    {
    po_object.selectedIndex = 0;
    }

    }
    po_object.previousIndex = po_object.selectedIndex;

    }

  5. gEEE..Thought this code was a little bit better :P So i call it beta.0.2

    try
    {
    var li_selIndex = po_object.selectedIndex;

    if(po_object.options[li_selIndex].disabled)
    {
    (!po_object.previousIndex)
    {
    po_object.previousIndex =0;
    }

    if(po_object.previousIndex > li_selIndex)
    {
    li_selIndex-=1;
    }
    else
    {
    li_selIndex+=1;
    }

    if(typeof(po_object.options[li_selIndex])==”object”)
    {
    po_object.selectedIndex=li_selIndex;
    }
    else
    {
    po_object.selectedIndex = 0;
    }
    po_object.previousIndex = po_object.selectedIndex;
    }
    return true;
    }
    catch(e){alert(e.description);}

  6. I modified the code so that it fixes some issues and behaves like other browsers that do support disable. For example if the first item is disabled you wouldn’t want it selected on page load.

    var focus_id;

    window.onload = function() {
    if (document.getElementById) {
    var select = document.getElementById(“someid”);

    window.select_current = new Array();
    select.onchange = function(){ restore(this); focus_id = this.selectedIndex; }
    emulate(select);
    }
    }

    function restore(e) {
    if (e.options[e.selectedIndex].disabled) {
    e.selectedIndex = focus_id;
    }
    }

    function emulate(e) {
    for (var i=0, option; option = e.options[i]; i++) {
    if (option.disabled) {
    option.style.color = “graytext”;
    }
    else {
    if (focus_id == null){
    focus_id = i;
    }
    }
    }
    e.selectedIndex = focus_id;
    }

  7. A little bit more improvement!

    /*parameter: po_object = select object*/
    function opt_disabled(po_object)
    {
    try
    {
    var li_selIndex = po_object.selectedIndex;

    if(po_object.options[li_selIndex].disabled)
    {
    if(!po_object.previousIndex)
    {
    po_object.previousIndex =0;
    }

    if(po_object.previousIndex > li_selIndex)
    {
    li_selIndex-=1;
    }
    else
    {
    li_selIndex+=1;
    }

    if(po_object.options[li_selIndex]!=null)
    {
    po_object.selectedIndex=li_selIndex;
    }
    else
    {
    po_object.selectedIndex = 0;
    }
    po_object.previousIndex = po_object.selectedIndex;
    }
    return true;
    }
    catch(e){alert(e.description)}
    }

  8. Here is my final solution that uses Al’s code, but is improved so it handles select boxes with multiple selection enabled. And it also uses window.attachEvent


    function selectFix()
    {
    if (document.getElementsByTagName)
    {
    var s = document.getElementsByTagName("select");
    if (s.length > 0)
    {
    window.select_current = new Array();
    for (var i=0, select; select = s[i]; i++)
    {
    if(select.multiple == true)
    {
    select.onfocus = function(){ window.select_current[this.id] = this.selectedIndex; }
    select.onchange = function(){ restoreMultiple(this);}
    emulateMultiple(select);
    }
    else
    {
    select.onfocus = function(){ window.select_current[this.id] = this.selectedIndex; }
    select.onchange = function(){ restore(this);}
    emulate(select);
    }
    }
    }
    }
    }

    function restore(e)
    {
    alert(e.options[e.selectedIndex].selected);
    if (e.options[e.selectedIndex].disabled)
    {
    e.selectedIndex = window.select_current[e.id];
    }
    e.blur();
    }

    function emulate(e)
    {
    var j = e.selectedIndex;
    var enabled = false;
    while(j

  9. Hi all, came across this page searching for a solution to this very problem (saved me having to work out IE was wrong not me – thanks for that alone)
    Unfortunately I could not get it to work.
    I tried your original JS (which crashed ie when i included it) plus I tried copying and pasting updated versions that were listed below.
    With those it generally moaned of “invalid characters”, I had a look through and noticed that they had things like ”someid” and “graytext” (notice angled quotes) – also with these I wasn’t sure if “someid” had to be changed for the id you were using.
    The last one, by Mihael Konjević // retro, seems to end early.

    Any chance of some help ? I am developing an open source mapping application and need to limit the combo box to certain values.
    My project is here: http://gmaps.evilc.com
    If you feel like being really helpful and having a go yourself, you can download the source from the link on the right of the map in the view mode box. It’s a 5 minute install once phpBB is installed, and when done you need gmaps.php, all you should need to touch is in the editZoomRange function. It already disables the options so it works in FireFox, all I need to do is get it working in IE6 too.
    Any work will of course be credited.
    I am generally looking for js / php coders to join the project, so if the whole thing interests you ( check out http://www.evilc.com/phpbb/viewtopic.php?t=2 for a bit of blurb on what I am trying to acheive ) then please drop me a line. I have just sourceforged the project, the project name is geoforum.

  10. I’d like to see something similar, but with visibility instead of disabled.

    There must be a way to hack IE into hiding the option instead of just disabling it, without having to remove and add options.

  11. More simple solution without color emulation.

    var lastValidIndex =0;
    function opt_disabled(select_object){
    try {
    var selIndex = select_object.selectedIndex;
    if(select_object.options[selIndex].disabled){
    select_object.selectedIndex = lastValidIndex;
    }
    else {
    lastValidIndex = select_object.selectedIndex;
    }
    return true;
    }
    catch(e){
    alert(e.description);
    }
    }

  12. Nice script(s), but…

    Does anyone have an equivalent which will allow me to display the tag’s VALUE when the user hovers over an option? I’d tried using onMouseOver(), onFocus() etc. before seeing this article and realizing that I’d been tearing my hair out in vain…giving up. This solution nicely disables certain elements, but I can’t seem to tweak it to display the VALUE… :(

    Rory

  13. Again, thanks for the great posts. Unfortunately I see that the multi-select post from Mihael is truncated, does anyone have rest of the script? or better a link to it?

  14. Hi,

    what would be the easiest way to implement this so that it still works onchange? ie without a submit button?

    Cheers
    Jayson

  15. Hi,

    what would be done if option to be disabled is
    the first one (e.g.”Choose one from list”)?
    Form still processes it.

    Sasha

  16. This is excellent post..and thanks for your great post..its really saved my time..

    regards
    -skonealone

  17. well once agin i thank.. but one problem i faced in it.. when i disabled some of options in it, after that i worte a javascript “OnChange” event but its not executing the “OnChange” event javascipt. infact its no executing any of the javascript in any select box event. can any one tell me why its not executing it ? as i tried alot.. still not get any way.. so pls help ..

    thanx in advance…

    regards
    -skonealone

  18. > use optgroup tag with label attribute instead of JavaScript.

    Sorry, could you please elaborate on this? Seems the person above me is having the same problem so would really help us out.
    :)

  19. Attempt: Use the JavaScript onclick event against the element, to again check if an has the disabled attribute in use.
    Problem: Internet Explorer doesn’t support the onclick event against a element

    Just a general comment on above ‘unsuccessful idea’ – You can use onChange event instead which is fully supported by IE.

    Anyway, I like your solution very much.
    Regards, M.D.

  20. The easiest way I’ve found to do one of these as a redirect is.

    Works in IE,Mozilla,Opera, Firefox, Netscape and AFAIK Safari.

    Though it doesnt work with javascript disabled.

  21. Nice solution, Al.

    Jayce, I too was intrigued by subz’ solution. I think he’s suggesting that we use “optgroup” in place of any disabled “options” since optgroups can’t be selected. Throw in a bit of CSS formatting, and you have a nice javascript-free solution. Here’s what worked for me.

  22. Wonderful workaround to the ugly beast IE. I had fully implemented disabled options on Firefox then found that IE is broken. I would love to use this solution, however, this is a commercial product. What are your feelings on this? I see your license excludes commercial.

  23. Does anyone have the code that Mihael Konjevic from post #9 wrote? It appears to be incomplete. I am interested in trying to handle multiple selects from a select box where some options are disabled. Thank you.

  24. I am not able to implement your solution
    Could u please send those script file so that i could test it out
    I would like to disable multiple items based on particular conditional logic

  25. Making heavy use of the concepts found here I have implemented an object-oriented version of this script. Head over to my article to download and see it in use.

    Sharon H. – this script will handle multiple selects from a select box where some options are disabled.

    Thanks again Al, great inspiration!

  26. This is an excellent thread.

    I am still fighting with the issue which Rory had mentioned earlier.

    How to get the value of highlighted option in a select box? I need to show a tooltip as the user hovers over each element of a select box.

  27. Hi guys, i know it’s never ending thing, but i’ve simplified the simpliest version for this stuff:

    function opt_disabled(select_object){
    try {
    var selIndex = select_object.selectedIndex;
    if(select_object.options[selIndex].disabled){
    while (select_object.options[selIndex].disabled) selIndex +=1;
    select_object.selectedIndex = selIndex;
    }
    return true;
    }
    catch(e){
    //alert(e.description);
    }
    }

    just to be clear:

    cheers

  28. Hi,

    This is a good solution… BUT… it doesn’t works if the select is inside an Microsoft AJAX UpdatePanel…

    Any solution to fix this?

  29. I had wasted so much time on this before finding your solution — it was getting hard to keep track of everything I’d tried. This pointed me in exactly the right direction to solve my particular problem.

    Thanks much.

  30. Hi,

    I have the same problem as Rory had but nobody posted any solution to Rory’s problem. tag doesn’t seem to entertain any HTML event. I want to display an option’s value in a tooltip but cant capture any event which can help me do this. I am about to give up on this one because I didn’t find no solution anywhere.

    For u guys’ convenience Rory posted the problem in post no 15.

    -Shaz

  31. What if in the list i would like to disable a selected item by means of a button. Can anyone help me?

    Say, there’s a list of 14 items, then i select one item out of the 14, then i click a button. After the button is clicked, the selected item should be disabled. Please help. Thanks.

  32. I didnt spot a mention of this simplistic but sometimes effective solution – set the value of ‘disabled’ options to something that can be picked up elsewhere by form processing logic and ignored, eg Name

    Not very elegant but simple and effective and doesnt need javascript/CSS etc…

  33. HOW TO CHECK THE STATUS OF TEXT BOX FROM INPUT TAG. i.e. HOW TO KNOW WEATHER TEXT IS DISABLED OR ENABLED.

    PL.REPLY,
    WITH CODE IF POSSIBLE.

  34. vijay,

    One option would be to put some standard HTML in the page and use JavaScript to disable/remove/hide it or you could also look into the <noscript> element as well.

    Al.

  35. thanks man. works for me :) ie is really a pain in the ass. disabled attribute works in firefox.

Comments are closed.