1

What I would like to do is to change the style of a select box in function of the number of options that it has. More specifically, I would like it to look like a span when there's only one option, and like a typical select element otherwise. In other words, I would like to hide the possibility of making a choice when there is no choice to make.

So far, the only solution I've found to this is to change the type of the tag back and forth from select to span, using jQuery and another SO answer, but since this is rather about styling, I would like to know about a pure CSS solution (or at least, CSS + jQuery solution).

Community
  • 1
  • 1
naitoon
  • 665
  • 5
  • 14
  • When there's no choice to make, make it disabled. – tymeJV Oct 18 '13 at 13:15
  • @tymeJV When there's no choice, why not add a class instead? – ediblecode Oct 18 '13 at 13:28
  • @tymeJV that doesn't really change the style. It just disables it. – naitoon Oct 18 '13 at 13:29
  • @jumpingcode That direction seems good, I tried that, but I don't know how to write CSS to define the style of that class in order to make a select element look like a span, say. – naitoon Oct 18 '13 at 13:33
  • @PragneshChauhan I want to know about the possibility of doing it, overall. I didn't tried to write code since I didn't know where I was heading. – naitoon Oct 18 '13 at 13:34
  • @jumpingcode I accepted your answer since I think is the one that most directly addresses the question I was asking. Thanks! – naitoon Oct 18 '13 at 15:26

4 Answers4

2

DEMO FIDDLE

CSS

select { 
    border: none;
    -webkit-appearance: none;
    font: inherit; 
}

select::-ms-expand {
    display: none;
}

select:focus {
    outline:none; 
    outline-offset:0; 
}

select > option {
    display:none; 
}

These select styles should only be applied to a <select> element with only one <option>

DEMO FIDDLE

jQuery

$('select').each(function(i, el) {
    if ($(el).children().length == 1) {
        $(el).css("display", "none"); // Hide it
        var optionVal = $(el).children().eq(0).text();
        $(el).after($("<span>" + optionVal + "</span>"));
    }
});

This will loop through every <select> on your page and then check if it has one option. If it does, it will hide the select and insert a span after.

ediblecode
  • 11,701
  • 19
  • 68
  • 116
  • it's not a crossbrowser solution this only works fine in google chrome – DaniP Oct 18 '13 at 13:50
  • Great @jumpingcode, you are answering the question. I'll wait some more time to see whether a completely cross-browser solution is proposed. – naitoon Oct 18 '13 at 14:01
  • Thanks @Danko for observing the non-cross-browser issue. – naitoon Oct 18 '13 at 14:01
  • @naitoon Unfortunately, there is no cross-browser solution. However, you might be able to do vendor specific styling. This works for IE + Chrome, and there are alternatives for getting it to work in Firefox so could have a Firefox rule. What are you using to render your HTML? – ediblecode Oct 18 '13 at 14:05
  • @jumpingcode I don't understand your question. Do you mean template rendering? – naitoon Oct 18 '13 at 14:11
  • @jumpingcode I'm using IE9 but it´s a great jump to get a complete solution – DaniP Oct 18 '13 at 14:12
  • @naitoon Yes that's what I mean. – ediblecode Oct 18 '13 at 14:16
  • BTW, @KenB answer has a reference to a an answer where they are able to style a select box in Firefox. – naitoon Oct 18 '13 at 14:17
  • @naitoon I've seen, but like I said, you'd need to write a rule specific to Firefox. – ediblecode Oct 18 '13 at 14:19
  • @naitoon What template rendering are you using? – ediblecode Oct 18 '13 at 14:25
  • @jumpingcode currently I'm not using one (I think I'll finish by using Django's default template engine), but I see where you're heading. That can be a great solution if the choices are known at rendering time (this is currently the case). I didn't think about that before. – naitoon Oct 18 '13 at 15:11
  • 1
    @naitoon I was thinking of you could have logic within the template to count the options, and then render a span or select based on this. – ediblecode Oct 18 '13 at 15:12
  • This is a really complicated way to go about it; why not just change the select into a span? – Ken Bellows Oct 18 '13 at 15:17
  • @jumpingcode I was also thinking about that. I'll evaluate that. – naitoon Oct 18 '13 at 15:19
  • @KenB It is an overly complicated solution – ediblecode Oct 18 '13 at 15:19
  • @KenB yes, and actually I'll take that approach (replacing select by span and vice-versa). My question was just to know whether another approach was possible. That's all. – naitoon Oct 18 '13 at 15:20
  • @jumpingcode it's 1 line of code (3 lines if you count looping through the ``s and checking how many children they have). That's doesn't seem too complicated to me. – Ken Bellows Oct 18 '13 at 16:57
1

There is no CSS functionality to determine how many options a select has; if that's the only check you're using, "Does it have multiple options?", then you're going to require some JavaScript.

In general, it's really hard to properly style a <select> with CSS, especially in a cross-browser way. See How to remove the arrow from a tag in Firefox for another user's struggle to do a similar thing. His solution might work for you, but it involves modifying the HTML, and if you're going to do that anyway, you might as well change it to a <span>.

EDIT:

Didn't realize you were also looking for a JavaScript solution. This is the simplest way to do it, and should be as cross-browser as jQuery:

$("select").each(function(i, elem){
    if ($(this).children().length == 1) {
        this.outerHTML = "<span>"+this.innerHTML+"</span>";
    }
});

http://jsfiddle.net/SfVp9/3/

Community
  • 1
  • 1
Ken Bellows
  • 6,711
  • 13
  • 50
  • 78
0

As I know there is no crossbrowser solution for CSS styling of SELECT. And that is why so many solutions maid with converting SPAN to SELECT-like object on the page.

0

If you give up on a pure CSS solution and decide to go with a combination CSS/JS solution. Here it is:

$("select").each( function(i) {
    if( this.length ==1) {
        var val = $(this).first().val();
        $(this).before("<span>" + val + "</span>");
        $(this).addClass("hidden");
    }
} );

JSFiddle Demo

At this point, you can style the span any way you want by adding a class to it as well.

SBerg413
  • 14,515
  • 6
  • 62
  • 88
  • I had a CSS+Jquery workaround as I said in the question (which is similar to this one), also involving adding/removing tags. I was interested in a CSS solution, maybe using a bit of Jquery for adding/removing classes, but not changing tags (i.e., not modifying structure, but only style). – naitoon Oct 18 '13 at 14:24
  • 1
    How about something where you have a pre-set already in the DOM with the value of the first option of the select. Then use js/jquery to just show hide either the select or span depending on the select count? At that point, it would only be modifying style/visibility. – SBerg413 Oct 18 '13 at 14:32
  • It's true. The problem is that when you have two elements, you need to take care of attributes. The workaround that I already have (cited in the question), has the ability of preserving the attributes of the tags you change. In what you propose, the attributes are lost. – naitoon Oct 18 '13 at 15:24