How to hide a Mark Sep 02 '13 at 16:32

  • 1
    It always returns the first option's value no matter what. – pixeldev Mar 11 '14 at 17:01
  • 10
    Interesting hack, but I would recommend avoiding "technically invalid HTML" if at all possible. – Luke Jun 26 '14 at 16:06
  • @Luke I'll keep that in mind when all browsers implement the same standards the same way. ;) – kitti Jun 26 '14 at 19:55
  • 3
    True, all browsers have different implementations. But one reason browsers cannot strictly implement the standard specs is because there is too much live code out there that doesn't follow the specs. IMO: If there are no other solutions, then by all means use a hack. But if you can follow the spec *and* solve your problem, why wouldn't you? It helps your code to play nice with others and helps to strengthen the spec. – Luke Jun 26 '14 at 20:38
  • @Mark thanks for your comment, but how would we then read the value of a hidden ` – James Cazzetta Nov 26 '15 at 12:39
  • As a note, this will no longer work on Chrome, since Chrome will enforce that `span` can't appear in select elements. Tried this on Chrome 60.0.3112.113 – Kolichikov Sep 19 '17 at 19:52
  • Safari won't accept this solution either. Though this method has fall. Don't know if there is another one. – Gustavo Mar 23 '20 at 19:33
  • 38

    I would suggest that you do not use the solutions that use a <span> wrapper because it isn't valid HTML, which could cause problems down the road. I think the preferred solution is to actually remove any options that you wish to hide, and restore them as needed. Using jQuery, you'll only need these 3 functions:

    The first function will save the original contents of the select. Just to be safe, you may want to call this function when you load the page.

    function setOriginalSelect ($select) {
        if ($select.data("originalHTML") == undefined) {
            $select.data("originalHTML", $select.html());
        } // If it's already there, don't re-set it
    }
    

    This next function calls the above function to ensure that the original contents have been saved, and then simply removes the options from the DOM.

    function removeOptions ($select, $options) {
        setOriginalSelect($select);
        $options.remove();
     }
    

    The last function can be used whenever you want to "reset" back to all the original options.

    function restoreOptions ($select) {
        var ogHTML = $select.data("originalHTML");
        if (ogHTML != undefined) {
            $select.html(ogHTML);
        }
    }
    

    Note that all these functions expect that you're passing in jQuery elements. For example:

    // in your search function...
    var $s = $('select.someClass');
    var $optionsThatDontMatchYourSearch= $s.find('options.someOtherClass');
    restoreOptions($s); // Make sure you're working with a full deck
    removeOptions($s, $optionsThatDontMatchYourSearch); // remove options not needed
    

    Here is a working example: http://jsfiddle.net/9CYjy/23/

    Luke
    • 18,811
    • 16
    • 99
    • 115
    • 1
      @DanBeaulieu There was a function named incorrectly in the previous jsfiddle. I fixed and updated the link above. Thanks for catching that. – Luke Jun 23 '15 at 17:49
    • Yes, this one was my choice as well. I actually managed to golf the code a bit smaller, by first taking the data value into a variable, if undefined, it will save the options, else it will restore options. My need was specific for such. – diynevala Jan 11 '18 at 10:14
    • 1
      I had to add `var value=$select.val(); $select.html(ogHTML); $select.val(value);` to keep selected value selected even after the restore. – diynevala Jan 11 '18 at 10:49
    • The cycle of selecting the options to remove and removing them only worked one time. After that, options.remove() had no effect for me. Once I moved the restoreOptions($s) call up a few lines so that I was always working with a full, fresh Select object, it worked. – Newclique Jul 24 '18 at 15:24
    18

    Ryan P's answer should be changed to:

        jQuery.fn.toggleOption = function (show) {
            $(this).toggle(show);
            if (show) {
                if ($(this).parent('span.toggleOption').length)
                    $(this).unwrap();
            } else {
                **if ($(this).parent('span.toggleOption').length==0)**
                    $(this).wrap('<span class="toggleOption" style="display: none;" />');
            }
        };
    

    Otherwise it gets wrapped in too many tags

    JeffT
    • 181
    • 2
    • 9
    • 5
      Note that according to the HTML specs (http://www.w3.org/TR/html5/forms.html#the-select-element), a ` – Luke Jun 26 '14 at 20:19
    9

    The toggleOption function is not perfect and introduced nasty bugs in my application. jQuery will get confused with .val() and .arraySerialize() Try to select options 4 and 5 to see what I mean:

    <select id="t">
    <option value="v1">options 1</option>
    <option value="v2">options 2</option>
    <option value="v3" id="o3">options 3</option>
    <option value="v4">options 4</option>
    <option value="v5">options 5</option>
    </select>
    <script>
    jQuery.fn.toggleOption = function( show ) {
        jQuery( this ).toggle( show );
        if( show ) {
            if( jQuery( this ).parent( 'span.toggleOption' ).length )
                jQuery( this ).unwrap( );
        } else {
            jQuery( this ).wrap( '<span class="toggleOption" style="display: none;" />' );
        }
    };
    
    $("#o3").toggleOption(false); 
    $("#t").change(function(e) {
        if($(this).val() != this.value) {
        console.log("Error values not equal", this.value, $(this).val());
        }
    });
    </script>
    
    Batiste Bieler
    • 309
    • 4
    • 7
    9

    Select inputs are tricky in this way. What about disabling it instead, this will work cross-browser:

    $('select').children(':nth-child(even)').prop('disabled', true);
    

    This will disable every-other <option> element, but you can select which ever one you want.

    Here is a demo: http://jsfiddle.net/jYWrH/

    Note: If you want to remove the disabled property of an element you can use .removeProp('disabled').

    Update

    You could save the <option> elements you want to hide in hidden select element:

    $('#visible').on('change', function () {
        $(this).children().eq(this.selectedIndex).appendTo('#hidden');
    });
    

    You can then add the <option> elements back to the original select element:

    $('#hidden').children().appendTo('#visible');
    

    In these two examples it's expected that the visible select element has the id of visible and the hidden select element has the id of hidden.

    Here is a demo: http://jsfiddle.net/jYWrH/1/

    Note that .on() is new in jQuery 1.7 and in the usage for this answer is the same as .bind(): http://api.jquery.com/on

    Community
    • 1
    • 1
    Jasper
    • 75,717
    • 14
    • 151
    • 146
    7
    // Simplest way
    
    var originalContent = $('select').html();
    
    $('select').change(function() {
        $('select').html(originalContent); //Restore Original Content
        $('select option[myfilter=1]').remove(); // Filter my options
    });
    
    Rene Berwanger
    • 157
    • 1
    • 2
    7

    Simple answer: You can't. Form elements have very limited styling capabilities.

    The best alternative would be to set disabled=true on the option (and maybe a gray colour, since only IE does that automatically), and this will make the option unclickable.

    Alternatively, if you can, completely remove the option element.

    Niet the Dark Absol
    • 320,036
    • 81
    • 464
    • 592
    4

    Since you're already using JS, you could create a hidden SELECT element on the page, and for each item you are trying to hide in that list, move it to the hidden list. This way, they can be easily restored.

    I don't know a way offhand of doing it in pure CSS... I would have thought that the display:none trick would have worked.

    Derreck Dean
    • 3,708
    • 1
    • 26
    • 45
    3

    You should remove them from the <select> using JavaScript. That is the only guaranteed way to make them go away.

    Jordan
    • 31,971
    • 6
    • 56
    • 67
    2

    !!! WARNING !!!

    Replace the second "IF" by "WHILE" or doesn't work !

    jQuery.fn.toggleOption = function( show ) {
        jQuery( this ).toggle( show );
        if( show ) {
            while( jQuery( this ).parent( 'span.toggleOption' ).length )
                jQuery( this ).unwrap( );
        } else {
            jQuery( this ).wrap( '<span class="toggleOption" style="display: none;" />' );
        }
    };
    
    Arraxas
    • 411
    • 5
    • 8
    2

    this one seems to work for me in chrome

    $("#selectid span option").unwrap();
    $("#selectid option:not([filterattr=filtervalue])").wrap('<span/>');
    
    exiled
    • 21
    • 3
    • 1
      Please add code format to your code, either by indenting with 4 spaces or wrapping your code with `. – dwitvliet Jul 17 '14 at 17:05
    • 1
      this code is great! it works on latest chrome, firefox and IE 11, that's good enough for me :) – Sijav Feb 24 '15 at 00:08
    • 1
      prior to my last comment, this thing works on IE 7 too! so ff 3.5, this is what I came up with at the last, it somehow on IE and chrome preserve the value that has been selected before options get hidden and if another value doesn't set after bringing back the options browser will set the option selected as before! – Sijav Feb 24 '15 at 00:53
    2

    Simply use option[value=your-value]{display:none;}

    This works fine in Chrome, at least in 2022, as well as in safari and FF.

    1

    Modern solution is simply apply CSS hidden like:

    <option value="" style="display:none;">Select Item</option>
    

    Or with a class

    <option value="" class="hidden">Please select</option>
    

    Note in class case, add css like

    .hidden {
      display: none;
    }
    
    M. Inam
    • 301
    • 3
    • 7
    0

    Late to the game, but most of these seem quite complicated.

    Here's how I did it:

    var originalSelect = $('#select-2').html();
    
    // filter select-2 on select-1 change
    $('#select-1').change(function (e) {
    
        var selected = $(this).val();
    
        // reset select ready for filtering
        $('#select-2').html(originalCourseSelect);
    
        if (selected) {
            // filter
            $('#select-2 option').not('.t' + selected).remove();
        }
    
    });
    

    markup of select-1:

    <select id='select-1'>
    <option value=''>Please select</option>
    <option value='1'>One</option>
    <option value='2'>Two</option>
    </select>
    

    markup of select-2:

    <select id='select-2'>
    <option class='t1'>One</option>
    <option class='t2'>Two</option>
    <option>Always visible</option>
    </select>
    
    RichardAtHome
    • 4,293
    • 4
    • 20
    • 29
    0

    Simply, this can achieved by HTML too.

    <select>
        <option value="" disabled selected hidden>Please Choose</option>
        <option value="0">hii</option>
        <option value="1">hello</option>
    </select>
    omkar
    • 47
    • 11
    0

    2022 Answer Summary And Cross-Browser Solution

    Currently, these methods do not work on Safari:

    • visibility: hidden
    • display: block
    • hidden attribute

    So none of proposed solutions here using these methods works on Safari, so they can not be accepted.

    Solution

    The solution is to keep special options in an array, and hide/restore them on-demand. For example to show/hide day selection based on year/month selection:

    When you initialize your component:

    const tailDayOptions = [];
    
      const saveTailDayOptions = () => {
        const daySelector = document.querySelector('#daySelector');
        for (let day = 29; day <= 31; day++) {
          tailDayOptions[day - 1] = daySelector.querySelector(`option[value='${day - 1}']`);
        }
      }
    

    When a user changes year or month:

    for (let day = 29; day <= 31; day++) {
          if (day <= daysInMonth) {
            daySelector.appendChild(tailDayOptions[day - 1])
          } else {
            const dayOption = daySelector.querySelector(`option[value='${day - 1}']`);
            if (dayOption) {
              daySelector.removeChild(dayOption);
            }
          }
        }
    

    How does it work

    1. It saves options for day 29,30 and 31 to a tailDayOptions array
    2. When user changes the year or month, daysInMonth are calculated
    3. If a given day (e.g. 29th) is not present in a given year-month and it is available in the select options, it gets removed from there
    4. If a given day is available in a given year-month it gets re-added to the select from the tailDayOptions array

    Compatibility

    Compatible with Firefox, Chrome and Safari. Should be compatible with all other browsers.

    Tom Smykowski
    • 25,487
    • 54
    • 159
    • 236