56

This should work:

$('option').hide(); // hide options

It works in Firefox, but not Chrome (and probably not in IE, not tested).

A more interesting example:

<select>
    <option class="hide">Hide me</option>
    <option>visible option</option>
</select>
<script type="text/javascript">
// try to hide the first option
$('option.hide').hide();

// to select the first visible option
$('option:visible').first().attr('selected', 'selected');
</script>

Or see the example at http://jsfiddle.net/TGxUf/

Is the only option to detach the option elements from the DOM? I need to show them again later, so this would not be very effective.

dave1010
  • 15,135
  • 7
  • 67
  • 64
  • You can use $('option:visible:first') instead of $('option:visible').first() – Diego Dec 09 '10 at 14:39
  • For anyone stumbling across this question now, note that the posted code *does* work in Chrome and Firefox (haven't tested IE). – Kat Jan 18 '15 at 23:14
  • 1
    The `:visible` selector isn't useful with ` – Sam Kauffman Sep 17 '15 at 15:02

16 Answers16

80

Unfortunately, you can't hide option elements in all browsers.

In the past when I have needed to do this, I have set their disabled attribute, like so...

$('option').prop('disabled', true);

I've then used the hiding where it is supported in browsers using this piece of CSS...

select option[disabled] {
    display: none;
}
alex
  • 479,566
  • 201
  • 878
  • 984
  • This is a good start, but I really need the options removed in all browsers. – dave1010 Dec 12 '10 at 18:44
  • 2
    @dave1010 Your only option then is to build an object of the `option`s, and remove and append as necessary. – alex Dec 12 '10 at 23:05
  • 2
    In case it's not clear from this answer. Disable and display none works in Firefox, Chrome and Edge but not IE or Safari (2018/2019) – png Jan 22 '19 at 18:25
  • Made a plain JS demo snippet while answering another question https://stackoverflow.com/questions/57511712/why-my-drop-down-list-is-working-in-all-the-browsers-except-ie11/57520289#57520289 – Jan Aug 16 '19 at 08:17
  • `hidden`? https://stackoverflow.com/a/24516786, https://caniuse.com/#feat=hidden – djvg Aug 12 '20 at 15:23
30

As has been said, you can't display:none individual <option>s, because they're not the right kind of DOM elements.

You can set .prop('disabled', true), but this only grays out the elements and makes them unselectable -- they still take up space.

One solution I use is to .detach() the <select> into a global variable on page load, then add back only the <option>s you want on demand. Something like this (http://jsfiddle.net/mblase75/Afe2E/):

var $sel = $('#sel option').detach(); // global variable

$('a').on('click', function (e) {
    e.preventDefault();
    var c = 'name-of-class-to-show';
    $('#sel').empty().append( $sel.filter('.'+c) );
});

At first I thought you'd have to .clone() the <option>s before appending them, but apparently not. The original global $sel is unaltered after the click code is run.


If you have an aversion to global variables, you could store the jQuery object containing the options as a .data() variable on the <select> element itself (http://jsfiddle.net/mblase75/nh5eW/):

$('#sel').data('options', $('#sel option').detach()); // data variable

$('a').on('click', function (e) {
    e.preventDefault();
    var $sel = $('#sel').data('options'), // jQuery object
        c = 'name-of-class-to-show';
    $('#sel').empty().append( $sel.filter('.'+c) );
});
Blazemonger
  • 90,923
  • 26
  • 142
  • 180
  • thanks for this answer, has helped me a lot.. Always nice when you can have a complete cross browser solution..this should be the accepted answer IMHO – Richlewis Feb 20 '15 at 14:53
  • This helped for me, key is to use $.detach() (or $.remove()) for max cross-browser compatibility instead of $.hide() – zaphodb Feb 17 '17 at 20:08
12

Had a crack at it myself and this is what I came up with:

(function($){

    $.fn.extend({detachOptions: function(o) {
        var s = this;
        return s.each(function(){
            var d = s.data('selectOptions') || [];
            s.find(o).each(function() {
                d.push($(this).detach());
            });
            s.data('selectOptions', d);
        });
    }, attachOptions: function(o) {
        var s = this;
        return s.each(function(){
            var d = s.data('selectOptions') || [];
            for (var i in d) {
                if (d[i].is(o)) {
                    s.append(d[i]);
                    console.log(d[i]);
                    // TODO: remove option from data array
                }
            }
        });
    }});   

})(jQuery);

// example
$('select').detachOptions('.removeme');
$('.b').attachOptions('[value=1]');');

You can see the example at http://www.jsfiddle.net/g5YKh/

The option elements are fully removed from the selects and can be re-added again by jQuery selector.

Probably needs a bit of work and testing before it works well enough for all cases, but it's good enough for what I need.

dave1010
  • 15,135
  • 7
  • 67
  • 64
  • 1
    I don't really want to have to accept my own answer but, unless anyone comes up with anything better, I may have to :-) – dave1010 Dec 12 '10 at 19:30
  • 3
    I had problems with dave1010's answer when running on IE8. The if (d[i].is(o)) call in the attachOptions function results in "object doesn't support this property or method" message. – DaveW Mar 05 '13 at 01:18
  • Here's how to complete the "TODO" section. You have to change the for-loop to "for (var i = 0; i < d.length; i++) { " and then add below TODO: "d.splice(i,1); i--;" – Matt Roy Feb 24 '15 at 16:05
10

I know this is a little late but better late than never! Here's a really simple way to achieve this. Simply have a show and hide function. The hide function will just append every option element to a predetermined (hidden) span tag (which should work for all browsers) and then the show function will just move that option element back into your select tag. ;)

function showOption(value){
    $('#optionHolder option[value="'+value+'"]').appendTo('#selectID');             
}

function hideOption(value){
    $('select option[value="'+value+'"]').appendTo('#optionHolder');
}
Matt T. McAlear
  • 131
  • 1
  • 6
  • 1
    Interesting idea. I guess the temporary container doesn't even have to be attached to the DOM (eg just created with with `document.createElement()`). – dave1010 Jul 30 '13 at 10:14
  • 1
    No idea why this andwer got downvoted. It does andwer the question, and does it well. – tomekwi Jan 14 '15 at 11:22
9

Hiding an <option> element is not in the spec. But you can disable them, which should work cross-browser.

$('option.hide').prop('disabled', true);

http://www.w3.org/TR/html401/interact/forms.html#h-17.6

Blazemonger
  • 90,923
  • 26
  • 142
  • 180
jAndy
  • 231,737
  • 57
  • 305
  • 359
8

You can try wrapping the option elements inside a span so that they wont be visible but still be loaded in the DOM. Like below

jQ('#ddlDropdown option').wrap('<span>');

And unwrap the option which contains the 'selected' attribute as follows to display already selected option.

var selectedOption = jQ('#ddlDropdown').find("[selected]");
jQ(selectedOption).unwrap();

This works across all the browsers.

6

Here's an option that:

  • Works in all browsers
  • Preserves current selection when filtering
  • Preserves order of items when removing / restoring
  • No dirty hacks / invalid HTML
$('select').each(function(){
    var $select = $(this);
    $select.data('options', $select.find('option'));
});
    
function filter($select, search) {
    var $prev = null;
    var $options = $select.data('options');
    search = search.trim().toLowerCase();
    $options.each(function(){
        var $option = $(this);
        var optionText = $option.text();
        if(search == "" || optionText.indexOf(search) >= 0) {
            if ($option.parent().length) {
                $prev = $option;
                return;
            }
            if (!$prev) $select.prepend($option);
            else $prev.after($option);
            $prev = $option;
        } else {
            $option.remove();
        }
    });
}

JSFiddle: https://jsfiddle.net/derrh5tr/

xxx
  • 1,153
  • 1
  • 11
  • 23
Wim Barelds
  • 294
  • 2
  • 9
5

On pure JS:

let select = document.getElementById("select_id")                   
let to_hide = select[select.selectedIndex];
to_hide.setAttribute('hidden', 'hidden');

to unhide just

to_hide.removeAttr('hidden');

or

to_hide.hidden = true;   // to hide
to_hide.hidden = false;  // to unhide
Andrey Topoleov
  • 1,591
  • 15
  • 20
3

Three years late, but my Googling brought me here so hopefully my answer will be useful for someone else.

I just created a second option (which I hid with CSS) and used Javascript to move the s backwards and forwards between them.

<select multiple id="sel1">
  <option class="set1">Blah</option>
</select>
<select multiple id="sel2" style="display:none">
  <option class="set2">Bleh</option>
</select>

Something like that, and then something like this will move an item onto the list (i.e., make it visible). Obviously adapt the code as needed for your purpose.

$('#sel2 .set2').appendTo($('#sel1'))
SpoonNZ
  • 3,780
  • 1
  • 20
  • 25
2

It's possible if you keep in object and filter it in short way.

<select id="driver_id">
<option val="1" class="team_opion option_21">demo</option>
<option val="2" class="team_opion option_21">xyz</option>
<option val="3" class="team_opion option_31">ab</option>
</select>

-

team_id= 31;

var element = $("#driver_id");
originalElement = element.clone();  // keep original element, make it global


element.find('option').remove();   
originalElement.find(".option_"+team_id).each(function() { // change find with your needs
        element.append($(this)["0"].outerHTML); // append found options
});

https://jsfiddle.net/2djv7zgv/4/

Fatih Alp
  • 209
  • 1
  • 3
  • 11
2

This is an enhanced version of @NeverEndingLearner's answer:

  • full browsers support for not using unsupported CSS
  • reserve positions
  • no multiple wrappings

$("#hide").click(function(){
  $("select>option.hide").wrap('<span>'); //no multiple wrappings
});

$("#show").click(function(){
  $("select span option").unwrap(); //unwrap only wrapped
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
<select>
    <option class="hide">Hide me</option>
    <option>visible option</option>
</select>
<button id="hide">hide</button>
<button id="show">show</button>
xam
  • 452
  • 2
  • 7
  • 15
1

Since you mentioned that you want to re-add the options later, I would suggest that you load an array or object with the contents of the select box on page load - that way you always have a "master list" of the original select if you need to restore it.

I made a simple example that removes the first element in the select and then a restore button puts the select box back to it's original state:

http://jsfiddle.net/CZcvM/

JayTee
  • 2,776
  • 2
  • 24
  • 27
  • That's a good idea. Unfortunately the code example you gave wouldn't run in Firefox. It would be nice to have a flexible jQuery plugin that could remove and re-attach `option` elements by arbitrary selectors. – dave1010 Dec 12 '10 at 18:47
0

just modify dave1010's code for my need

 (function($){
    $.fn.extend({hideOptions: function() {
        var s = this;
        return s.each(function(i,e) {
            var d = $.data(e, 'disabledOptions') || [];
            $(e).find("option[disabled=\"disabled\"]").each(function() {
                d.push($(this).detach());
            });
            $.data(e, 'disabledOptions', d);
        });
    }, showOptions: function() {
        var s = this;
        return s.each(function(i,e) {       
            var d = $.data(e, 'disabledOptions') || [];
            for (var i in d) {
                $(e).append(d[i]);
            }
        });
    }});    
})(jQuery);

http://jsfiddle.net/AbzL3/1/

pavlickm
  • 21
  • 3
0

I thought I was bright ;-)

In CSS:

option:disabled {display:none;}

In Firefox and Chrome, a select with only the enabled options were created. Nice.

In IE, the enabled options were shown, the disabled where just blank lines, in their original location. Bad.

In Edge, the enabled options shown at top, followed by blank lines for disabled options. Acceptable.

Leif Neland
  • 1,416
  • 1
  • 17
  • 40
0

Try this:

$(".hide").css("display","none");

But I think it doesn't make sense to hide it. if you wanna remove it, just:

$(".hide").remove();
Tee Wu
  • 569
  • 2
  • 9
  • I don't think the `option` have a `display` attribute. Also, he says he needs to show the `option`s again later, so `remove()` ing them and not keeping a way to return them isn't useful to the OP. – alex Dec 09 '10 at 14:28
  • @alex: thanks for reminding me man. I just type it so quick. I wanna type css instead....thanks!! – Tee Wu Dec 09 '10 at 14:35
  • i agree, if there is an item in a list that you dont always want there, make it a part of the options list, generate the select tag, and then in the right scenario, remove the option you want to hide. – raddrick Aug 13 '14 at 18:28
0

document.getElementById('hide').style.visibility='hidden';

ive used id here for option