Building an accessible, client-side chained selection drop down

View Comments

A chained selection drop down, or as I like to call it, “a dynamic drop down,” is a series of single-selection <select> boxes chained together. What makes these selection drop downs chained together is that the options in each drop down are dependent on the selected option in the drop down preceding it. Now, I’ve seen plenty of solutions for this online, but I have not come across a solution that functions when JavaScript is disabled. So, I decided to come up with a solution by building a jQuery plugin.

The dynamic drop down jQuery plugin in action

Here’s a quick example of the dynamic drop down jQuery plugin in action:

Source:

<select id="example">
    <option value="jquery">Tutorials » JavaScript » jQuery</option>
    <option value="codeigniter">Tutorials » PHP » CodeIgniter</option>
    <option value="wordpress">Tutorials » PHP » WordPress</option>
    <option value="xhtml-css">Tutorials » XHTML/CSS</option>
    <option value="blog">Blog</option>
    <option value="security">Articles » Security</option>
    <option value="design">Articles » Design</option>
</select>
<script type="text/javascript">$("#example").dynamicDropdown();</script>

The usefulness of dynamic drop downs

Chained select boxes or “dynamic drop downs” are useful for large selection lists. Let’s say that your user has to select an item from a list of a hundred items or so. A list of that length can be selected from the same way that many of us select our country or state from large drop downs: by typing the name of the item that we want to select. However, you can’t always expect your user to be able to type their desired selection.

  • Your user may not know the correct spelling of the item that they would like to select,
  • Your user is not aware that they can type their selection and, instead, manually navigates the drop down, as I’ve witnessed in less-experience computer users, or
  • Your user may not know which option they are looking for (i.e. a user may want a “headset” but think that they are called “headphones”).

Let’s also consider that, unlike a listing of states or countries, your options are not listed in alphabetical order. Once again, navigating this drop down becomes more difficult.

Building the drop down

Now, let’s imagine that your lengthy list can be categorized into small selections. Let’s take the example of a list of car models. Just in case you are unfamiliar with automobile terminology, the model of the car is the name of the car and the make of the car is the name of the company that produced the vehicle. So, for the Ford Focus, Ford is the make and Focus is the model. I’m sorry that I had to explain that, but I’ve encountered enough people that have confused the make and model.

Your user must select their current make, model, and year. So, you will need to build your drop down with options in that format. You must select to use a delimiter as well. If all of your options are guaranteed to be a single word, then a space will suffice. However, this isn’t always the case, so the default delimiter that our jQuery plugin will use is &raquo; (“»”) surrounded on both sides by a space. Here’s what our <select> box will look like:

<select>
    <option value="mustang2000">Ford » Mustang » 2000</option>
    <option value="mustang2005">Ford » Mustang » 2005</option>
    <option value="focus">Ford » Focus » 2010</option>
    <option value="alero">Oldsmobile » Alero » 1993</option>
</select>

One thing to note about the jQuery plugin that I’ve built is that you do not have to have the same amount of levels in every option. The jQuery plugin is very flexible and will allow your users to select options of any depth. So, for example, you could build the above drop down with an extra option:

<select>
    <option value="mustang2000">Ford » Mustang » 2000</option>
    <option value="mustang2005">Ford » Mustang » 2005</option>
    <option value="focus">Ford » Focus » 2010</option>
    <option value="alero">Oldsmobile » Alero » 1993</option>
    <option value="other">Other</option>
</select>

How you build these options is up to you. If your options are in your database, you can use SQL JOINS to combine them using your delimiter. Or, if you need the values of each element of the option, you could combine the values in the value attribute of your <option> elements with a dash as a delimiter. This jQuery plugin is built to be flexible and shouldn’t get in the way of retrieving the values that you need.

Using the dynamic drop down jQuery plugin

Firstly, you need to download the JS file. You can get the development version of the dynamic drop down jQuery plugin (includes instructions in the header comments) or the minified production version of the dynamic drop down jQuery plugin. Right-click the link that you want and select “Save Link As…” (or whatever variation your browser has for this option) to download it. Please, save these to your server instead of linking to them from here. Then, include both jQuery and the dynamic drop down plugin in your page. After that, you can call the script on an element by either:

  • Putting the following JavaScript in the <head> element wrapped in a $(document).ready() function, or
  • Placing the following JavaScript in the <body> element, anywhere after the target <select> element has been created.

The JavaScript code

In the following code, replace the generic select selector with the CSS selector for your targeted element(s). The object that is passed to the dynamicDropdown() function contains the options. The default options set the delimiter to " » " and the className to "dynamic-dropdown".

  • The delimiter option refers to the string that is used to separate the different levels in the chained selections. It’s worth noting that, due to different encoding formats, you may need to define the delimiter option, even if you plan on using the default delimiter.
  • The className option refers to the class attribute that is given to the resulting <select> boxes. This is for formatting purposes.
$("select").dynamicDropdown({
    "delimiter" : " » ",
    "className" : "dynamic-dropdown"
});

Reading the selection

After you have made a selection you will want to be able to access the selection that was made. Your original <select> box remains intact when you use this jQuery plugin, and its value is dependent on the selection made in the chained selection. So, you simply take the value from the original <select> box as you would any other <select> box.

How does the dynamic drop down work?

The dynamic drop down jQuery plugin works by:

  • Reading your <select> box,
  • Building an array of chained selections,
  • Hiding the original <select> box while still preserving it,
  • Building <select> boxes based on the current selections and the array of chained selections, and
  • Modifying the value of the original <select> box for submission.

What are the limitations?

Due to the way this plugin functions, it is limited in some forms. This is due to my desire for simple and graceful code. There are plans to overcome these limitations in future releases.

  1. Values cannot be defined on a partial path of an existing path. In other words, this is invalid:
    <select>
        <option value="example">Example</option>
        <option value="inner-example">Example » Inner Example</option>
    </select>
    There are plans to implement this capability in the future. In fact, if you can think of a graceful solution to this, feel free to share it and it will be a part of the official release.
  2. Users cannot select each option in steps. Most chained selection boxes work as a step-by-step process in which the succeeding selection boxes are hidden or disabled until a selection is made. While this is not a default, it is possible to implement by creating options that mimic this functionality. This will be implemented as a plugin option in a future release.

Conclusion

This plugin is still in beta and may have a glitch or two in it. I have personally tested in Google Chrome 7, Firefox 4 Beta, and Internet Explorer 6 (just covering the bases). For those that may have missed the links to the source, here they are again. Just right-click the link that you want and select “Save Link As…” (or whatever variation your browser has for this option) to download it.

If you run into any problems, or would simply like to throw some praise my way, feel free to leave a comment.

Did you like this? Share it:
  • Test

    This is cool but I can’t seem to read the data… like I’m testing with an alert but nothing…

  • Test

    Okay I just tried with a button and the alert worked… However, instead of showing the selected value, it always just shows the first option, it doesn’t check the selection properly – any ideas?

  • Test

    Nevermind, I found it:

    onclick=”alert(document.getElementById(‘select’).options[document.getElementById('select').selectedIndex].value);”

  • Test

    This works really nicely – is there a way to choose which option is selected by default when the page is loaded?

    Eg, say your data is like this:

    Ford » Mustang » 2000
    Ford » Mustang » 2005
    Ford » Focus » 2010
    Oldsmobile » Alero » 1993

    (ie, there is a “selected” on the Ford Mustang 2005)

    It’d be good if this could be selected on the dynamic drop down as well.

  • http://koviko.net/ Kovik

    Yes, you can select the initial selection of the dynamic drop down by selecting the initial selection of the static drop down before calling the dynamicDropdown() function. You do this by using the “selected” attribute or by selecting it using jQuery (e.g. $(element).attr(“selected”, true);). The plugin should be able to handle the rest

  • Walt

    Hey Kovik. This is really awesome work. Thank you. Have you been able to work on any new versions lately as you mentioned in the article?

  • http://koviko.net/ Kovik

    I regret that I have not. I’m still in the midst of deciding what I even want to do with this domain. Before I change the site, I’ll be sure to put this plugin onto github.

  • bvpowell

    First off … THANKS! I have been scouring dev sites and forums trying to find a simple solution to the dynamic drop down and by chance I just started using JQuery to build my site.

    I’m using your plug-in to generate a make and model search as in your example as well as PHP/MySQL to build the list. Is there a way to have the first dynamically generated model selection as “ANY” so that the user can search for all models within a make category?

    In response to your reply to the previous post … I know it must be time/money consuming to maintain the blog, but I’m very glad I stumbled across this.

  • http://koviko.net/ Kovik

    That is an interesting dilemma. I honestly can’t think of a way to do something like that without huge overhaul within the code. As of now, the code is fairly minimal (and thanks to `eval`, a bit difficult to follow). In its current state, the addition of a catch-all would require the catch-all to simulate every level.

    While I certainly don’t consider this most efficient method, the only way to do that as of now is to build all of those elements into an ANY category. To avoid making your HTML messy by doing so, do it in JavaScript.

    $(function() {
        var delimiter = ” » “;
        var selectElement = $(“#example”);
        var selectOptions = selectElement.children(“option”);
        var firstSelectOption = selectOptions.first();
        
        selectOptions.each(function() {
            var option = $(this);
            var optionText = option.html();
            var textToReplace = optionText.split(delimiter, 1)[0];
            if (optionText.length > textToReplace.length) {
                var finalText = ”ANY” + optionText.substr(textToReplace.length);
                var newOption = $(document.createElement(“option”), {value: option.val()})
                    .text(finalText)
                    .insertBefore(firstSelectOption);
            }
        });
        
        selectElement.val(selectElement.children(“option”).first()).dynamicDropdown();
    });

    Let me know if there are any issues.

  • Harry

    Hi Kovik, thanks for the great plugin!

  • http://koviko.net/ Kovik

    Glad to see people are still getting use out of this. :)

  • Harry

    Hi again,

    I’ve been testing the plugin since yesterday and I’ve stumbled in a weird bug. Since I’m really bad with Javascript, I couldn’t pinpoint the reason for this problem. Would you have any quick fix for this?:

    When I use the “selected” attribute as an initial value, only the first option from the same root level gets selected. To make this more clear:

    Computers » Lenovo
    Computers » HP
    Cars » BMW » 320
    Cars » BMW » 420
    Cars » Smart » 402

    Would actually show “Cars » BMW » 320″ as the initial value because it’s the first option of the Cars root. 

    I also tried a modified version of this by Andrew Smiley, but that had some other bugs which might take even more time to fix.

    Sorry to bother you about this, but I would greatly appreciate this fix, since it’s crucial for my upcoming site. I’ve tried the production and development versions. Both have the same bug. I’m also willing to donate some money for this fix, in case you have a PayPal account for donations.

  • http://koviko.net/ Kovik

    That certainly is a bug, one resulting from a lovely copy-paste typo. The culprit is on line 140. Change “buildDynamicDropdown” to “initializeDynamicDropdown”. I’ll upload the fix to this server, shortly.

    As for your offer of a donation, it is certainly appreciated. The email in the JS file is now capable of accepting PayPal donations. Thank you. :)

  • Harry

    Hi Kovik,

    thank you once again! Unfortunately this didn’t fully fix it. Now the initial selection stays in the first option of the second level of the selected branch.

    To make it more clear:

    Computers » LenovoComputers » HPCars » Smart » 402Cars » BMW » 320Cars » BMW » 420Cars » BMW » 520
    would result in “Cars » BMW » 320″ to initially selected (because 320 is the first leaf of the “Cars » BMW” branch.

    I still respect your work greatly, so I already made a small donation and hope you’d have the time to fix this last bug. :)

  • http://koviko.net/ Kovik

    Ah, you’re right. I never built in the final selection code. It is now added in and uploaded here as v1.0.2. :)

  • Harry

    Wonderful, thanks a bunch!

  • Nizam Kazi

    Hi, I want something silimar for wordpress, can you develop one? or is it anyway to use this one in wordpress? Please reply

  • http://koviko.net/ Kovik

    This blog is WordPress and it is being used here. All you have to do is include the JS file and follow the instructions written here.

  • Harry

    Hi Kovik,

    sorry to bother you again. I tried to email you, but I never got an answer. Maybe my mails got to your spam folder? Anyways, I’ve got a small issue once again. Would be great if you’d be able to fix this.

    I have this job form which can be in different states. When the status of a job changes, I update the state of the job to match the status. I have the following list of states:

    Onsite work» Not started

    Onsite work » Finished

    Off-site work » Not started

    Off-site work » Not ready

    Off-site work » Finished

    Remote work » Not started

    Remote work » Not ready

    Remote work » Finished

    If I change the state to any other and update, it will work just fine. The problem comes if I don’t change the state but update the form. In that case the state always changes to a Remote work (last of the first level options in the list). So if I have Off-site work » Not started selected while I update the form, it will automatically change to Remote work » Not started. If I have Onsite work » Finished selected, it will change to Remote work » Finished etc…

    So only the first level is changed, but the second level will always stay intact. If I’d have a 3-level option selected, it wouldn’t cause any problems at all. This happens only if I have a 2-level option selected with identical 2nd level item in the Remote work level.

    Just to make things more clear: if I change the state from Off-site work » Not started to anything else and then return it back to Off-site work » Not started, it will work just swell.

    Would you happen to have any ideas on this?

  • http://koviko.net/ Kovik

    I did respond. Try downloading the latest version (1.0.5) from here and let me know if that solves your problem.

  • rafal

    rafaHello, thanks for such a gret plugin.

    Could you please point me how to get the data-price values and place it in #price (onchange event)? Thanks a lot in advance

    Size : M » Color : White » Polo Shirt : Yes
    Size : L » Color : White » Polo Shirt : Yes
    Size : L » Color : Red » Polo Shirt : Yes
    Size : S » Color : Green » Polo Shirt : No
    Size : S » Color : Green » Polo Shirt : Yes

  • http://koviko.net/ Kovik

    In the plugin’s current state, it’d be difficult to make any events occur with onchange events because of how the elements are added to and removed from the DOM. However, whenever the form is submitted, you can use the value to find the corresponding element in the original element (it still exists in the DOM), and then get the data-* attributes from it.

  • rafal

    Hi
    I did it!
    In case someone will find it helpful,
    am creating an array

    prices = new Array()
    $(“#options option”).each(function(){
    prices[$(this).val()] = $(this).attr(‘data-price’);
    })
    and passing the array to your plugin
    jQuery(“#options”).dynamicDropdown({“delimiter”:” » “, “arrayPrices”: prices});
    then in your script adding
    $(‘.price’).html(settings.arrayPrices[$(this).val()]);

    Great script
    Thanls

blog comments powered by Disqus