Grow your CSS skills. Land your dream job.

So You Need To Fill a Dropdown Dynamically

Published by Chris Coyier

You have one dropdown menu, and depending on the user's choice in that one, a second dropdown gets filled with choices. Let's cover three different ways you can go about that.

View Demo   Download Files

The Markup

For our example, the markup will always be the same, just two simple select elements. The first one has three options. The first just informs the user to select an option, and the next two are actual choices. The second select only has one option telling the user to please pick from the first dropdown first. The options in the second dropdown will be dynamically replaced.

<select id="first-choice">
	<option selected value="base">Please Select</option>
	<option value="beverages">Beverages</option>
	<option value="snacks">Snacks</option>
</select>

<br />

<select id="second-choice">
	<option>Please choose from above</option>
</select>

Option 1: Using Text Files

The idea for this post came from Robert Young who wrote to me sharing this technique. The idea is that it's easy to use and understand. Not everybody wants to deal with databases and whatnot.

Have one text file for each possibility:

Inside those text files, have the replacement HTML for new options ready to go:

<option>Coffee</option>
<option>Coke</option>

Now we'll use jQuery to watch for the changing of the first select. All our examples will use jQuery.

$("#first-choice").change(function() {
   $("#second-choice").load("textdata/" + $(this).val() + ".txt");
});

This works fine. It is indeed easy to do. The potential downsides are 1) storing data in HTML tags like that may not be the way to go, hard to repurpose that data for other reasons. 2) not super scalable, requiring a new text file for every single possibility.

Option 2: Using JSON Data

An alternative is to store the data that you need in JSON format. You could have it right in your JavaScript that you are loading, or keep it in an external file. For this demo it will be an external file called data.json. This is its contents:

{
	"beverages": "Coffee,Coke",
	"snacks": "Chips,Cookies"
}

We again watch for a change in the first select's value, then load the JSON and figure out which parts of it we need:

$("#first-choice").change(function() {

	var $dropdown = $(this);

	$.getJSON("jsondata/data.json", function(data) {
	
		var key = $dropdown.val();
		var vals = [];
							
		switch(key) {
			case 'beverages':
				vals = data.beverages.split(",");
				break;
			case 'snacks':
				vals = data.snacks.split(",");
				break;
			case 'base':
				vals = ['Please choose from above'];
		}
		
		var $secondChoice = $("#second-choice");
		$secondChoice.empty();
		$.each(vals, function(index, value) {
			$secondChoice("<option>" + value + "</option>");
		});

	});
});

The advantage here is that we are storing the data fairly generically, so it would be easy to repurpose it for other things. Notice we add the option tags in the JavaScript itself, that's pretty flexible. The downsides to this technique is that it's a bit more complicated (but really, it's not that bad). We might want to consider breaking up the JSON into separate files so we don't need to load all data on every change, but then we run into the same scalability issue as text files. Having the database return us JSON is also a possibility here.

Option 3: Using a Database

We're still going to watch the first select with jQuery, and still load in the new options dynamically with jQuery's .load() function. But to pull from a database, we'll need an intermediary partner that can do that database talking for us (JavaScript can't do that by itself). So we'll use a file "getter.php", and that will be the file that returns us what we need.

First we'll need a very simple database to pull from:

CREATE TABLE `dd_vals` (
  `index` int(11) NOT NULL,
  `category` varchar(255) NOT NULL,
  `dd_val` varchar(255) NOT NULL,
  UNIQUE KEY `index` (`index`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

INSERT INTO `dd_vals` (`index`, `category`, `dd_val`) VALUES (1, 'snacks', 'Chips'),
(2, 'snacks', 'Cookies'),
(3, 'beverages', 'Coffee'),
(4, 'beverages', 'Coke');

Now we can query that database, in the "dd_vals" table for entries that have snacks or beverages as their category and get just what we want. Our query needs to end up something like this:

SELECT * FROM dd_vals WHERE category='beverages'

So let's make our getter.php file connect to that database, and have a GET parameter for the category choice, plug that into the query, and return what it finds in option tags.

<?php

	$username = "username";
	$password = "password";
	$hostname = "localhost";
	
	$dbhandle = mysql_connect($hostname, $username, $password) or die("Unable to connect to MySQL");
	$selected = mysql_select_db("dropdownvalues", $dbhandle) or die("Could not select examples");
	$choice = mysql_real_escape_string($_GET['choice']);
	
	$query = "SELECT * FROM dd_vals WHERE category='$choice'";
	
	$result = mysql_query($query);
		
	while ($row = mysql_fetch_array($result)) {
   		echo "<option>" . $row{'dd_val'} . "</option>";
	}
?>
Keith Silgard wrote in to help me make sure this was secure. Whenever you run a database command with data that you recieve via POST or GET, you need to make sure that data is safe. As in, it doesn't contain incredibly malious code like "; DROP TABLE ... ", which is commonly known as SQL injection. This code has been updated to use mysql_real_escape_string to ensure that doesn't happen. Also note this function only works properly if used after the database connection is established.

Now our JavaScript is really simple, we again watch for changes to the first dropdown and load in the getter.php file into the second dropdown. The fancy trick here is to pass the getter.php file URL parameter which is the value from the first dropdown.

$("#first-choice").change(function() {
	$("#second-choice").load("getter.php?choice=" + $("#first-choice").val());
});

For very little website and isolated examples, a database can feel like a lot of work or even overkill, but this is easily the most flexible option. The code is clean, it's fast, the data is stored in a way we can do just about anything with it, etc.

That's not all?

Like anything on the web, there are even more ways to approach this. We could have stored the values in an associate array. We could have used MongoDB. We could have had the different selects ready to go in the HTML and hide-and-show them as needed with JavaScript. They all have advantages and disadvantages.

View Demo   Download Files

Note: I'm not including the database example in the download because it won't work until you have your own database to connect to and all that. It'll just be less confusing that way.

Comments

  1. This is a great tut and very useful! Thanks Chris!

  2. Reza
    Permalink to comment#

    gr8

  3. Permalink to comment#

    This is so cool. It used to be a lot of work and code to do this. Great work!

  4. Permalink to comment#

    Really nice tutorial, i’ve already done a similar script but in a little different way but yours is very cool ! I’ve learn some function that i have not seen before.

    Have a nice day

  5. Permalink to comment#

    Great stuff as always Chris, thanks!

  6. Drew
    Permalink to comment#

    Looks like the ‘Please select’ option is missing a value in the demo.

    <pre>
    <option value=”base”>Please choose from above</option>
    </pre>

  7. I really like the different options. Great tutorial and thanks for the tips.

  8. Florent Halm
    Permalink to comment#

    For the last bit of code, shouldn’t $(“#db-one”).val() be $(this).val() or $(“#first-choice”).val()!?

  9. James
    Permalink to comment#

    Could you make a stand-alone version of the database demo work by using SQLite?

    • I don’t know much about SQLite, but that’d be rad. If you can get it worked I’d be glad to do a follow up article.

  10. cristi
    Permalink to comment#

    hello,

    i did create the database and the files and it doesn’t work.
    thanks,

    i have an index.html

    
    
    
    	
    		$(function() {
    		
    			$("#db-one").change(function() {
    				$("#db-two").load("getter.php?choice=" + $("#db-one").val());
    			});
    		
    		});
    	
    
    
    
    
    
    
    			Please Select
    			Beverages
    			Snacks
    		
    	
    		
    	
    		
    			Please choose from above
    
    		
    	
    
    
    
    and getter.php
    
    <?php
    
            $choice = $_GET['choice'];
    
            $username = "ridegrabbd";
            $password = "Character123";
            $hostname = "ridegrabbd.db.6717737.hostedresource.com";
    
            $dbhandle = mysql_connect($hostname, $username, $password) or die("Unable to connect to MySQL");
            $selected = mysql_select_db("dropdownvalues", $dbhandle) or die("Could not select examples");
    
            $query = "SELECT * FROM dd_vals WHERE category='$choice'";
    
            $result = mysql_query($query);
    
            while ($row = mysql_fetch_array($result)) {
                    echo "" . $row{'dd_val'} . "";
            }
    ?>
    
  11. Dave Allen
    Permalink to comment#

    Now where did I just see that? ;) http://screenr.com/AKZ

  12. Very cool tutorial, and waaaaaay easier than I thought it would be.

  13. Jeff Dion
    Permalink to comment#

    Nice approach,

    For further bullet proofing the functionnality, you could make the whole system work in php using the same table that you actually have


    +-------+----------+----------+
    | index | category | dd_val |
    +-------+----------+----------+
    | 1 | snack | chips |
    | 2 | snack | Cookies |
    | 3 | beverage | Coke |
    | 4 | beverage | Coffee |
    +-------+----------+----------+

    in the first drop down you only load the categories and in the second you load all the dd_vals. Once the user submit the form you cross-check if the category fits with the dd_val, if you get a match proceed as planned, otherwise throw an error.

    Once this part works, you had a jquery layer to populate the second list with the right dd_vals based on the category selected in the first drop down.

    This way, you have a nice fallback if javascript doesn’t work (either because the user have deactivated the feature in his browser or because there is a bug in the javascript itself)

  14. Steven Albano
    Permalink to comment#

    I enjoy reading your articles. For the json portion, I would suggest:

    {
    "beverages": "Coffee,Coke",
    "snacks": "Chips,Cookies"
    }

    be changed to

    {
    "beverages": ["Coffee", "Coke"],
    "snacks": ["Chips", "Cookies"]
    }

    It uses a few more characters, but captures the intent of the data structures better.

    • Steven Albano
      Permalink to comment#

      In addition, it removes the need for calling the split method as the values are already in an array.

    • Exactly what I was about to say :) Using JSON as it was intended.

  15. bob
    Permalink to comment#

    Being the javascript fan I am, I was looking for a comment like yours Steven ;) Using an array for that listing woud allow you to write something like

    vals = data[key] || ['Please choose from above'];

    Which gets the listing from data by key, and if it is undefined it falls back to ['please choose']

    But that may just be besides the point of this article, which does a good job showing some of your options.

  16. David
    Permalink to comment#

    This is awesome, thanks a ton man.

    I was rackin’ my brain a few months ago trying to figure this out…. ended up giving up.

  17. Salman
    Permalink to comment#

    Thanks for the tutorial, Just great, as it’s already been said, used to be lots of coding, and now just a simple nice easy to understand two line of jquery and php.

  18. Permalink to comment#

    The PHP code is open to SQL injection attacks, since you’re not escaping the $choice variable. In addition, you’re using the old MySQL library (which is now deprecated), so it will only work with MySQL. I’d suggest changing it to use PDO, which is newer and works with a few databases (SQLite, PostgreSQL, MySQL among others).

    See: http://www.webdevrefinery.com/forums/topic/1272-your-mysql-code-sucks/

  19. Thanks for an excellent post on dynamic dropdowns and three ways of approaching, some nice ideas, we like to use databases as said for flexibility, clean code and scalability. LT

  20. david
    Permalink to comment#

    I agree with Steven Albano and I would add the base value to the json instead of keeping it in the code.

    The adding of the options isn’t working because there is no function call.

    Check the jsfiddle to see how i would write the code.

  21. The MySQL variety is a little clunky compared to the other two, sometimes the request can be so slow it takes several seconds. Probably something to stay away from unless there is no alternative.

  22. Permalink to comment#

    Argh.. i see deprecated mysql_*-Function.

    Good Tut anyway.

  23. Leo Rapirap
    Permalink to comment#

    Hi Chris great tuts. I downloaded the files and works fine and easy to follow however it does not work on Google Chrome (works fine in FF though). Am I the only one experiencing this issue?

  24. Osama
    Permalink to comment#

    Hi,

    Thanks for this great tutorial ;)

    I had a problem with dynamic dropdowns using a database.

    I made 3 menu: the second depends on the first, the third depends on the second.
    But there is a probleme. The second contains some elements with spaces and elements from one word.
    For element with one word everything is ok.
    But when i select an element composed from two parts (that contain space) the third menu don’t show any result!

    What do you think? what’s the probleme with spaces?!

  25. Osama
    Permalink to comment#

    I found the solution:

    you need to add escape() for the variable!!! and no more problems with spaces ;)
    escape($(this).val())
    Maybe you better add this to your code to be perfect :D

    $(“#first-choice”).change(function() {
    $(“#second-choice”).load(“textdata/” + $(this).val() + “.txt”);
    });

    Bye, and thanks again

  26. toni
    Permalink to comment#

    @cristi

    I uploaded Option 3: Using a Database here: http://rapidshare.com/files/428684871/dropdown.rar

    Put the ‘dropdown’ folder in your ‘www’ folder. In phpMyAdmin create new database and name it ‘dropdown’. Then import the file dd_vals.sql, which can be found into the rar file and you are good to go. Hope it helps.

  27. Permalink to comment#

    It’s nice to see such advanced design topics discussed in such detail. I’ve been doing web design for quite a few years now, and I really wish resources like this had been around back when I started. I probably would have gotten a lot further with my web design career.

  28. salas
    Permalink to comment#

    I also couldn’t get the JSON example to work (missing function call when pushing select options onto $secondChoice). David’s jsfiddle link helped a lot.

  29. James
    Permalink to comment#

    Hello, in regards to using the text files method.. How would you expand the code to allow for more than two drop down fields?

    List 1 populates list 2…
    List 2 populates list 3…
    List 3 populates list 4…

    Thank you.

  30. Ripon
    Permalink to comment#

    Hi,

    I have seen your tutorial. it seems it is very easy way to handle drop down menu. but sorry to say i can get output. the error message i am receiving is ” Undefined index: choice in”

    need your help.

    Ripon

  31. Rui Fernandes
    Permalink to comment#

    Hey there,
    your tutorial is very helpfull but im having trouble with the third example. if you could upload again (link is bronken) it would be nice.
    If its not ask to much i would like to do everything without making a external file like getter.php.

  32. Josh
    Permalink to comment#

    Sorry How do you change or add more options to this drop down system.

Leave a Comment

Current day month ye@r *

*May or may not contain any actual "CSS" or "Tricks".