26

My problem is HTML and CSS related. I have a hierarchy type structure that I want to display inside a list. The hierarchy contains Countries, States and Cities (it is three levels deep).

I want to display the list inside a select list, each item type (Country, State, City) must be selectable. The items should appear indented as:

United States
- Hawaii
-- Kauai
- Washington
-- Seattle
-- Chelan

The problem is with the indentation. I am trying to use either margin-left or padding-left to indent the tags, which appear correct in FireFox but not in IE7. This is an example of the generated select list:

<select name="Something">
<option style="padding-left: 0">United States</option>
<option style="padding-left: 20px">Hawaii</option>
<option style="padding-left: 40px">Kauai</option>
<option style="padding-left: 20px">Washington</option>
<option style="padding-left: 40px">Seattle</option>
<option style="padding-left: 40px">Chelan</option>
</select>

I want to achieve consistent indentation across browsers without using CSS hacks.

Kara
  • 6,115
  • 16
  • 50
  • 57
Salman A
  • 262,204
  • 82
  • 430
  • 521

8 Answers8

51

The rendering of SELECT elements is largely up to the browser, you have very little influence over their presentation. Some browsers obviously allow you more customization than others, IE happens to allow very little (gasp, who'd have thunk ;)). If you need very custom SELECT elements, you'll need to employ JavaScript or re-create something that behaves like a SELECT but is made of a bunch of DIVs and checkboxes or something to that extend.

Having said that, I think what you're looking for are OPTGROUPs:

<select>
  <optgroup label="xxx">
    <option value="xxxx">xxxx</option>
    ....
  </optgroup>
  <optgroup label="yyy">
    ...
  </optgroup>
</select>

Every browser will display them differently, but they'll be displayed in a distinctive fashion in one way or another. Note though that officially in HTML4 you can't nest OPTGROUPs.

deceze
  • 510,633
  • 85
  • 743
  • 889
  • 1
    As a fallback you could always display them like you did in the example, indenting them using dashes --. – deceze Jul 18 '09 at 05:53
  • 1
    @deceze Quoted from the question: "each item type (Country, State, City) must be selectable". I doubt optgroup is selectable. – o.k.w Jul 18 '09 at 07:25
  • True that. Then he needs to either group them differently and use the group label as, well, label, or simply skip the second part of my answer. – deceze Jul 18 '09 at 11:50
  • 3
    Ummm... optgroups cannot be nested i think, I mean, I might use optgroups for country level but then I cannot use them for states. – Salman A Jul 20 '09 at 05:44
25

deceze way is much better and was my first idea. As an alternative if that doesn't work is that you can use non-breaking spaces in the tag value:

<select>
    <option>select me</option>
    <option>&nbsp;me indented</option>
    <option>&nbsp;&nbsp;even more indentation</option>
</select>

It's far from pretty but it might work for you if the optgroup doesn't.

John Flatness
  • 32,469
  • 5
  • 79
  • 81
MacAnthony
  • 4,471
  • 2
  • 23
  • 26
  • 3
    I'm afraid this is the most reliable solution indeed. – Ms2ger Jul 18 '09 at 09:59
  • 11
    This isn't good solution, because search by letter doesn't work. – MicTech Jul 08 '10 at 06:41
  • If by "search by letter" you mean typing to get the result, then I don't think that should be a terribly big motivator. That feature/functionality is very browser specific on how it works and IMO, isn't widely utilized by normal users. If that isn't what you are referring to, then I'm afraid I don't know what you are talking about. – MacAnthony Jul 12 '10 at 14:37
  • 2
    seems that Chrome faithfully renders the   verbatim. I had to use hyphens – Anentropic Sep 24 '13 at 16:12
  • 3
    ` `'s indent in Chrome is small and is also rendered as the selected value. If this is undesirable, try ` ` – evilkos Jul 03 '17 at 11:42
13

Just for the sake of visitors, I feel I should share this solution I devised: http://jsfiddle.net/n9qpN/

Decorate the options with the level class

<select name="hierarchiacal">
<option class="level_1">United States</option>
    <option class="level_2">Hawaii</option>
        <option class="level_3">Kauai</option>
    <option class="level_2">Washington</option>
        <option class="level_3">Seattle</option>
        <option class="level_3">Chelan</option>
</select>

We can now use jQuery to reformat the content of the select element

$(document).ready(
function(){
   $('.level_2').each(
        function(){
            $(this).text('----'+$(this).text());
        }
   );

   $('.level_3').each(
        function(){
            $(this).text('---------'+$(this).text());
        }
   );

 }
);

This can be extended to any level

codingbiz
  • 26,179
  • 8
  • 59
  • 96
6

Try using &#160;

<select name="Something">
  <option>United States</option>
  <option>&#160;Hawaii</option>
  <option>&#160;&#160;Kauai</option>
  <option>&#160;Washington</option>
  <option>&#160;&#160;Seattle</option>
  <option>&#160;&#160;Chelan</option>
</select>
Igor Krupitsky
  • 787
  • 6
  • 9
2

Isn't this method of grouping creating more problems than it solves? As a user, which of those am I supposed to choose? Is there any benefit to choosing something more specific than country?

If the issue is that you only have one database field to store them in, why not have three separate select boxes (making 2 or 3 optional) and just store the most specific?:

<select name="country">
    <option>Choose a country</option>
    <option>United States</option>
</select>
<select name="state">
    <option>Choose a state</option>
    <option>Hawaii</option>
</select>
<select name="city">
    <option>Choose a city</option>
    <option>Kauai</option>
</select>
Simon Scarfe
  • 9,378
  • 4
  • 28
  • 32
  • I'll have to do a cascaded "onchange=populate_next_select();" for this purpose. Besides, what I want is to present the entire list in one galance. – Salman A Jul 20 '09 at 05:53
  • @Salman A: Why so? You're fully-populating the one-select box anyway, so why not fully-populate all 3? However, your point about providing the entire list at once is a fair one. – Simon Scarfe Jul 20 '09 at 08:21
  • 7
    >> "Why so?" The client said so :( – Salman A Jul 22 '09 at 10:04
  • 4
    Hi, I'm from the year 2017. The client is still 'always right'. – a20 May 14 '17 at 05:12
1

I was able to accomplish this using the NO-BREAK SPACE unicode character. http://www.fileformat.info/info/unicode/char/00a0/index.htm

Copy-paste the character from that page into code and voila: https://jsfiddle.net/fwillerup/r9ch988h/

(&nbsp; didn't work for me because I was using a library for fancy select boxes that would inject them verbatim.)

fredw
  • 1,409
  • 12
  • 23
1

Prepending Non breaking space (&nbsp) did not work for me.

I prepended the following:

String.fromCharCode(8194);

Skywalker
  • 1,717
  • 1
  • 22
  • 25
0

I like the solution suggested by @codingbiz above: https://stackoverflow.com/a/11600605/6730120

I modified a jquery code slightly, to be more generic. So, instead of defining each of the possible levels manually in the script, use data-level attribute to define the place in the hierarchy. Note: it is your responsibility to put meaningful values, so the hierarchy makes sense.

Check the snippet.

$('select.hierarchy').each(function() {

        $(this).children('option').each(function(){

            attr = $(this).attr('data-level');

            multiplier = 1;   // increase the value, if you want larger indents, i.e. 3
            indent = (typeof attr !== 'undefined' && attr !== false) ? parseInt(attr) * multiplier : 0;

            $(this).html("&nbsp;".repeat(indent) + $(this).text());
        });
        
    });
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<select class="hierarchy" id="select" name="select">
<option value="NULL"></option>
<option value="1" data-level="0">Option 1</option>
<option value="2" data-level="1">Option 1.1</option>
<option value="3" data-level="2">Option 1.1.1</option>
<option value="4" data-level="1">Option 1.2</option>
<option value="5" data-level="0">Option 2</option>
<option value="6" data-level="1">Option 2.1</option>
<option value="7" data-level="1">Option 2.2</option>
<option value="8" data-level="2">Option 2.2.1</option>
</select>
Kuba
  • 161
  • 2
  • 7