Submit your widget

A Drop Down with Icon (CSS and jQuery)

Created 14 years ago   Views 17666   downloads 2749    Author n/a
A Drop Down with Icon (CSS and jQuery)
View DemoDownload
105
Share |

For me,standard HTML Select element is pretty much annoying. It's ugly. It can't be styled properly in Internet Explorer. And it can't contain nothing but simple text. That is the reason why I needed to reinvent Drop Down element.

Simple structure

Let me explain HTML structure that will be used here. In this example we will use a short list of 8 countries. List is created using Definition List (DL) element. Why this element? It is similar to unordered/ordered list - the only difference is that DL consists of two elements: DT (term) and DD (definition). This makes it perfect candidate for Drop Down element. Element DT can be used to show collapsed state with currently selected option while DD can show all the available options in nested UL. Here is the sample structure:

<dl class="dropdown">
    <dt><a href="#"><span>Please select the country</span></a></dt>
    <dd>
        <ul>
            <li><a href="#">Brazil</a></li>
            <li><a href="#">France</a></li>
            <li><a href="#">Germany</a></li>
            <li><a href="#">India</a></li>
            <li><a href="#">Japan</a></li>
            <li><a href="#">Serbia</a></li>
            <li><a href="#">United Kingdom</a></li>
            <li><a href="#">United States</a></li>
        </ul>
    </dd>
</dl>

 

In order to make Drop Down functional we have to add several important CSS styles. First of all we have to reset margins and paddings for DD, DT and UL. DD will be positioned relatively, so that nested UL can be absolutely positioned. As I mentioned earlier, in collapsed state, only DT will be visible. It contains link with span inside it and two elements make sliding doors, a technique that is often used for creating buttons and tabs. Styling UL is simple, it will be positioned 2px below DT and initially hidden.

/* General dropdown styles */       
.dropdown dd, .dropdown dt, .dropdown ul { margin:0px; padding:0px; }
.dropdown dd { position:relative; }
/* DT styles for sliding doors */
.dropdown dt a {background:#e4dfcb url(arrow.png) no-repeat scroll right center;
    display:block; padding-right:20px; border:1px solid #d4ca9a; width:150px;}
.dropdown dt a span {cursor:pointer; display:block; padding:5px;}
/* UL styles */
.dropdown dd ul { background:#e4dfcb none repeat scroll 0 0; display:none;
    list-style:none; padding:5px 0px; position:absolute; 
    left:0px; top:2px; width:auto; min-width:170px;}
.dropdown span.value { display:none;}
.dropdown dd ul li a { padding:5px; display:block;}

 

Let's make it work

It's time to involve jQuery. Each click on DT (actually link inside DT) will toggle nested UL

$(".dropdown dt a").click(function() {
    $(".dropdown dd ul").toggle();
});

 

This was the simplest part. Now let's simulate other features of Select element. When you choose an option from the list (UL) it become selected option and is shown inside the link in DT. The function below replaces the HTML of currently selected item with the inner HTML of clicked link. At the end, it hides nested UL.

$(".dropdown dd ul li a").click(function() {
    var text = $(this).html();
    $(".dropdown dt a span").html(text);
    $(".dropdown dd ul").hide();
}); 

 

This looks more like Drop Down, but there are still some things that need to be done. First, once you reveal nested UL by clicking on Drop Down it remains visible. And that's a bug. Although there can be better solutions, I've came up with this one:

$(document).bind('click', function(e) {
    var $clicked = $(e.target);
    if (! $clicked.parents().hasClass("dropdown"))
        $(".dropdown dd ul").hide();
});

 

The function above checks each click on a page and if click occurred on some elements outside the dropdown it hides nested UL. Now this looks like regular Select element.

What about selected value?

Although it looks fine it will surely become a headache for developers. Select element has "value" attribute where you can store some data then needs to be sent to the server. This attribute is usually populated by ID's of records stored in the database. In our example with list of countries, it is more likely that some country ID will be needed for any serious processing on the server. So how to store these values and how to get selected one?

Let's modify HTML structure from the beginning of this tutorial and add <span> element inside links in UL. Each <span> have class "value" and real value inside it.

<dl class="dropdown">
    <dt><a href="#"><span>Please select the country</span></a></dt>
    <dd>
        <ul>
            <li><a href="#">Brazil<span class="value">BR</span></a></li>
            <li><a href="#">France<span class="value">FR</span></a></li>
            <li><a href="#">Germany<span class="value">DE</span></a></li>
            <li><a href="#">India<span class="value">IN</span></a></li>
            <li><a href="#">Japan<span class="value">JP</span></a></li>
            <li><a href="#">Serbia<span class="value">CS</span></a></li>
            <li><a href="#">United Kingdom<span class="value">UK</span></a></li>
            <li><a href="#">United States<span class="value">US</span></a></li>
        </ul>
    </dd>
</dl>

 

It would be strange to have codes next to country names in the list, so let's hide these spans.

.dropdown span.value { display:none;}

 

And that is the only change we'll need to make in order to make this Drop Down fully functional. Take one more look at click handler for links in UL - it replaces inner HTML of link in DT with inner HTML of clicked link. This means tha tlink in DT element will have <span> with value included.

var text = $(this).html();
$(".dropdown dt a span").html(text);

 

It's easy now to get selected value from our Drop Down. You can create a function like the one below to extract selected value. As the matter of fact, the very same function extracts selected value in the demo and shows this value under the Drop Down.

function getSelectedValue(id) {
    return $("#" + id).find("dt a span.value").html();
}

 

The code works in all major browsers: Firefox, Safari, Google Chrome, Opera(9.64), Internet Explorer 7 and 8. It works even in IE6, althoug it needs some polishing :)