Get The Drop On ASP.NET MVC DropDownLists
DropDownList, ComboBox, call it what you like, but it always renders as an html select element. It has an opening <select> tag, and a closing </select> tag. In between, each "ListItem" is housed within an <option> tag. Optionally, they may be subdivided into <optgroup> elements for logical separation of related options. If you provide a value attribute to an option, that is the value that gets posted back when a form housing the select element is submitted. If you omit the value attribute, the text value of the option gets posted back.
At its simplest, for example if you have a static list of items that needs to appear in a DropDown, you can simply put them in your View as html:
<select name="year"> <option>2010</option> <option>2011</option> <option>2012</option> <option>2013</option> <option>2014</option> <option>2015</option> </select>
Or, if the list is a little more dynamic, say if you need to ensure that the starting year is incremented by 1 each New Year's Day:
[WebForms] <select name="year"> <option><%= DateTime.Now.Year %></option> <option><%= DateTime.Now.AddYears(1).Year %></option> <option><%= DateTime.Now.AddYears(2).Year %></option> <option><%= DateTime.Now.AddYears(3).Year %></option> <option><%= DateTime.Now.AddYears(4).Year %></option> <option><%= DateTime.Now.AddYears(5).Year %></option> </select>
[Razor] <select name="year"> <option>@DateTime.Now.Year</option> <option>@DateTime.Now.AddYears(1).Year</option> <option>@DateTime.Now.AddYears(2).Year</option> <option>@DateTime.Now.AddYears(3).Year</option> <option>@DateTime.Now.AddYears(4).Year</option> <option>@DateTime.Now.AddYears(5).Year</option> </select>
Or even:
[WebForms] <select name="year"> <% for (var i = 0; i < 6; i++){%> <option><%= DateTime.Now.AddYears(i).Year %></option> <%}%> </select>
[Razor] <select name="year"> @for (var i = 0; i < 6; i++){ <option>@(DateTime.Now.AddYears(i).Year)</option> } </select>
All of the above will render exactly the same html and end result:

If your data comes from a database, you will more likely use one of the 8 overloads of the Html.DropDownList() extension method to create your DropDown. I won't cover all overloads, but it is worth looking at the main ones. The first one - public static string DropDownList(this HtmlHelper htmlHelper, string name) - simply accepts a string. Now the documentation currently says that the string should be the name of the form field, which isn't particularly helpful. In fact, not only does it provide the resulting select element with a name and an id, but it also acts as the look-up for an item in the ViewBag having the same dynamic property as the string provided. This ViewBag property is then bound to the helper to create the <option> items. Consequently, the ViewBag property must be a collection of SelectListItems. Here's how to get the Categories from the Northwind sample database using LINQ to SQL to pass to a DropDownList using the first overload:
public ActionResult Index() { var db = new NorthwindEntities(); IEnumerable<SelectListItem> items = db.Categories .Select(c => new SelectListItem { Value = c.CategoryID.ToString(), Text = c.CategoryName }); ViewBag.CategoryID = items; return View(); }
Notice that each SelectListItem must have a Value and a Text property assigned. These are bound at run-time to the value attribute of the option elements and the actual text value for the option. Notice also the odd name given to the ViewBag dynamic property "CategoryID". The reason for this is that the CategoryID is the value that will be passed when the form is submitted, so it makes sense to name it like this. In the View, the overload is used:
[WebForms] <%= Html.DropDownList("CategoryID") %>
[Razor] @Html.DropDownList("CategoryID")
And that's all that's needed to render the following HTML:
<select id="CategoryID" name="CategoryID"> <option value="1">Beverages</option> <option value="2">Condiments</option> <option value="3">Confections</option> <option value="4">Dairy Products</option> <option value="5">Grains/Cereals</option> <option value="6">Meat/Poultry</option> <option value="7">Produce</option> <option value="8">Seafood</option> </select>
The second overload - public static string DropDownList(this HtmlHelper htmlHelper, string name, IEnumerable<SelectListItem> selectList) - is one you quite often see in examples. With this overload, you can return an IEnumerable<SelectListItem> collection or a SelectList object. We'll have a look at the View first, before seeing two methods of populating the ViewData with alternative objects:
[WebForms] <%= Html.DropDownList("CategoryID", (IEnumerable<SelectListItem>) ViewBag.Categories) %>
[Razor] @Html.DropDownList("CategoryID", (IEnumerable<SelectListItem>) ViewBag.Categories)
The first item to go into ViewBag will be the IEnumerable<SelectListItem> object. The code is pretty well identical to the previous example:
public ActionResult Index() { var db = new NorthwindDataContext(); IEnumerable<SelectListItem> items = db.Categories .Select(c => new SelectListItem { Value = c.CategoryID.ToString(), Text = c.CategoryName }); ViewBag.Categories = items; return View(); }
The second passes a SelectList object to ViewBag:
public ActionResult Index() { var db = new NorthwindDataContext(); var query = db.Categories.Select(c => new { c.CategoryID, c.CategoryName }); ViewBag.Categories = new SelectList(query.AsEnumerable(), "CategoryID", "CategoryName"); return View(); }

Using a SelectList is slightly tidier in the Controller, and arguably in the View. The SelectList constructor has a couple of overloads which accepts an object representing the selected value:
public ActionResult Index() { var db = new NorthwindDataContext(); var query = db.Categories.Select(c => new { c.CategoryID, c.CategoryName }); ViewBag.CategoryId = new SelectList(query.AsEnumerable(), "CategoryID", "CategoryName", 3); return View(); }
The above will ensure that "Confections" is selected when the list is rendered:

Default Values
All of the examples so far show the first selectable option visible when the page loads. Most often, however, a default value is desirable, whether this is a blank value or a prompt to the user to "--Select One--" or similar. Another overload takes care of adding this - public static string DropDownList(this HtmlHelper htmlHelper, string name, IEnumerable<SelectListItem> selectList, string optionLabel).
[WebForms] <%= Html.DropDownList("CategoryID", (SelectList) ViewBag.CategoryId, "--Select One--") %>
[Razor] @Html.DropDownList("CategoryID", (SelectList) ViewBag.CategoryId, "--Select One--")

CSS and HTML attributes
Four of the overloads accept parameters for applying HTML attributes to the DropDownList when it is rendered. Two of them accept IDictionary<string, object> while the other two take an object. The object is an anonymous type. The following examples will both render identical html, applying a css class selector and a client-side onchange() event:
[Webforms] <%= Html.DropDownList( "CategoryID", (SelectList)ViewBag.CategoryId, "--Select One--", new Dictionary<string, object> { {"class", "myCssClass"}, {"onchange", "someFunction();"} }) %> <%= Html.DropDownList( "CategoryID", (SelectList)ViewBag.CategoryId, "--Select One--", new{ //anonymous type @class = "myCssClass", onchange = "someFunction();" }) %>
[Razor] @Html.DropDownList( "CategoryID", (SelectList)ViewBag.CategoryId, "--Select One--", new Dictionary<string, object> { {"class", "myCssClass"}, {"onchange", "someFunction();"} }) @Html.DropDownList( "CategoryID", (SelectList)ViewBag.CategoryId, "--Select One--", new{ //anonymous type @class = "myCssClass", onchange = "someFunction();" })
You should notice that the second version (the one using the anonymous type) has a property called "@class". This will render as a literal "class", but needs the @ sign in front of "class" because class is obviously a C# keyword. You might also wonder why there are two ways to add attributes. The second option, using the anonymous object is a lot cleaner and surely would be the sensible choice. However, for one thing, the HTML5 specification includes the ability to add custom attributes to your html mark-up. Each attribute must be prefixed with "data-". If you attempt to create a property in a C# object with a hyphen in its name, you will receive a compiler error. The Dictionary<string, object> approach will solve that problem.
Where's My AutoPostBack?
One of the most common questions from developers used to the Web Forms model concerns AutoPostBack for DropDownLists in MVC. In Web Forms, it's easy enough to select your DropDownList in design view, head over to the Properties panel in your IDE and set AutoPostBack to true, or to tick the Use AutoPostBack option on the control's smart tag. Quite often, since it is that easy, developers give little thought to what happens behind the scenes when AutoPostBack is used. In fact, an onchange attribute is added to the rendered DropDownList, which fires a javascript event handler, causing the form in which the DropDownList is housed to be submitted. This process has to be done manually within MVC. But it's quite simple. I'll show two ways of achieving this. One will use the most recent overload (above) which takes an object for htmlAttributes, and the other one will show how the same thing can be done using jQuery, unobtrusively. I haven't actually shown DropDownLists within a form element so far, but of course a DropDownList is useless outside of one. Here's the first alternative:
[WebForms] <% using (Html.BeginForm("Index", "Home", FormMethod.Post, new { id = "TheForm" })){%> <%= Html.DropDownList( "CategoryID", (SelectList) ViewData["Categories"], "--Select One--", new{ onchange = "document.getElementById('TheForm').submit();" })%> <%}%>
[Razor] @using (Html.BeginForm("Index", "Home", FormMethod.Post, new { id = "TheForm" })){ @Html.DropDownList( "CategoryID", (SelectList) ViewData["Categories"], "--Select One--", new{ onchange = "document.getElementById('TheForm').submit();" }) }
And the second that uses jQuery:
<script type="text/javascript"> $(function() { $("#CategoryID").change(function() { $('#TheForm').submit(); }); }); </script>
[WebForms] <%using (Html.BeginForm("Index", "Home", FormMethod.Post, new { id = "TheForm" })){%> <%=Html.DropDownList("CategoryID", (SelectList) ViewBag.CategoryId, "--Select One--") %> <%}%>
[Razor] @using (Html.BeginForm("Index", "Home", FormMethod.Post, new { id = "TheForm" })){ @Html.DropDownList("CategoryID", (SelectList) ViewBag.CategoryId, "--Select One--") }
ToolTips
Nothing in the existing set of HtmlHelpers for DropDownLists provides for adding tool tips to select list options at the moment. Tool tips are generated by adding a "title" attribute to each option in the list. Now, this could be achieved by creating your own extension methods that allow you to specify that each option element should have a title, and then apply a value to the title attribute as each option is added to the select list. But that's a fair amount of work... Or, you could use jQuery to do this really easily:
<script type="text/javascript"> $(function() { $("#CategoryID option").each(function() { $(this).attr({'title': $(this).html()}); }); }); </script>

Strongly Typed Helper
All of the examples so far have illustrated the use of the dynamic ViewBag collection to pass values from Controllers to Views. There are strongly typed Html Helpers for the DropDownList to cater for strongly typed views - with all that Intellisense support and compile-time checking. The following example shows a very simple ViewModel class called SelectViewModel:
using System.Collections.Generic; using System.Web.Mvc; public class SelectViewModel { public string CategoryId { get; set; } public IEnumerable<SelectListItem> List { get; set; } }
Here's a sample controller action that instantiates a SelectViewModel instance and passes it to the strongly type view:
public ActionResult Index() { var db = new NorthwindDataContext(); var query = db.Categories.Select(c => new SelectListItem { Value = c.CategoryID.ToString(), Text = c.CategoryName, Selected = c.CategoryID.Equals(3) }); var model = new SelectViewModel { List = query.AsEnumerable() }; return View(model); }
Notice how the selected item is identified as the IEnumerable collection of SelectListItems is built from the database query. Finally, in the (Razor) view, the dropdown is rendered with a default option added:
@model SelectViewModel @Html.DropDownListFor(m => m.CategoryId, Model.List, "--Select One--")
Currently rated 4.71 by 136 people
Rate Now!
Date Posted:
07 January 2010 21:27
Last Updated:
30 April 2011 12:00
Posted by:
Mikesdotnetting
Total Views to date:
183730



Comments
08 January 2010 04:22 from Mike Sharp
Hi, Mike, Could you provide a printable version of the article?
And my name is Mike too :)
09 January 2010 04:41 from ali62b
Hi Mike,
Can you post and example how to bind DropDown in Edit scenarios?
(The selected value should be the one that saved in DB already and can select another one when saving. I think this is more related to Model Binding but is very useful in dropdown related issues)
Thanks in advance.
09 January 2010 08:37 from Mikesdotnetting
@Mike
That's something I've been meaning to do. Watch this space
@ali62b
I was thinking about looking at that separately.
11 January 2010 17:12 from Dave Hanna
Mike,
I experienced a significant amount of confusion between the Html.DropDownList(name), and the Html.DropDownList(name, selectList) overloads, that you might want to expound on. In the first, the name variable identifies the select list as well as the selected item. When going to the second overload (forced by my need to use HtmlAttribute parameter, which isn't available with just the "name" overload), I assumed that the select list was the same one named by the name parameter. But the name parameter really changes function in the second overload to be a string or string array specifying the selected items.
11 January 2010 19:51 from Mikesdotnetting
@Dave
. If there isn't a matching item, an exception is thrown. That's all it does really. There is no selected itme if you use that overload. You must use one of the overloads where you explicitly pass in the selected item's value.
In the first overload (string name), there is no variable for selectlist passed in, so the source code looks for an item in ViewData that has the same key as the value of name, and checks to see if it can be cast as an IEnumerable
All of the overloads that allow you to specify htmlAttributes require the selectList to be passed in explicitly. Download the source code for MVC and look at the SelectExtension.cs file.
18 January 2010 15:26 from ali62b
Today I found a post which covers editing scenarios with DropDownList. here is the address :
http://odetocode.com/Blogs/scott/archive/2010/01/18/drop-down-lists-and-asp-net-mvc.aspx
However wanted to know if this is a preferred way in your opinion or not.
20 January 2010 13:45 from Mikesdotnetting
@ali62b
Thanks for the link to Scott's article. My personal preference is for strongly typed views, so yes - I would prefer to work with DropDownLists in the way he describes. But as with all these things, it's up to the developer to make the right decision in the context of the project he/she is working on. It's not for me to dictate what is right or wrong for other people.
Unless of course they don't agree with me :o)
14 March 2010 16:06 from Mike J
Perhaps I am thick. Is the mechanism you described for choosing a default value the approach to take when editing and matching the the selection to the users previous choice?
14 March 2010 16:40 from Mikesdotnetting
@Mike J
The default value is the one you normally see as the first one. What you need is one of the overloads that accepts a value for the Selected value.
19 May 2010 00:36 from Jason
Mike, Is there a way for the client to enter text into the ddl instead of just selecting from the static list?
20 May 2010 15:27 from Mikesdotnetting
@Jason
No. You are referring to something equivalent to a VB style Combo Box. In order to make one of those, you need to fiddle around with a Text box and a div, plus some CSS. There is no HTML Combo box as such.
08 July 2010 02:52 from Atta ur Rahman
Hi... thanx for the nice article
but i want something more , can you please add ,how can i retrive dropdown selected item in my action controller after form submit....
not just the selected value , but both selected text and value in my FormCollection or any other way....
08 July 2010 05:29 from Mikesdotnetting
@Atta
There is no such thing as "selected text" in MVC. You can either do a lookup on your database to get the text associated with the posted value, or you can combine whatever you have as your current value and text, and make that the value. Then you can parse each item out when the form is posted back.
23 July 2010 07:49 from John
Is there someway to do combobox in MVC? We want to convert a webform app that has 15 comboxes in a row. When they are not dropped down, they are nicely narrow and fit. When we click one of them, it widens and shows the contents. How to do this in MVC? Can we use the Ajax combobox as we did in the webform app?
23 July 2010 08:24 from Mikesdotnetting
@John,
Comboboxes are generally nothing more than a text box with an image to ape the dropdown botton, a div and some css and javascript. I tend to steer clear of ASP.NET AJAX stuff and look for jQuery alternatives. Google or Bing should help you.
21 January 2011 19:58 from San
Thanks for the Article. It helped me a lot to understand.
06 May 2011 06:31 from Gregg
Thank you very much...I was having trouble applying Html Attributes to a dropdown list but this article really helped!
27 April 2012 15:11 from Araik
Thanks!
14 May 2012 15:29 from Gift White
this is what
I was looking for :)
thank you
20 May 2012 09:13 from seyhan bakır
thank you..very usefull post
27 May 2012 13:33 from Jade Tibbitts
Thanks For This. After Pissing around for hours on end your article was the only one in which could help me. So Big Thanks
13 June 2012 13:36 from Stanislava Pavlova
Hi :) I want to ask something... Is this working in MVC2? Couse i'm trying but it doesn't work... I want to know if it's my mistake :) Thanks in advance!
14 June 2012 21:52 from Mikesdotnetting
@Stanislava,
Yes, the code will work with MVC 2. You should post a question at http://forums.asp.net
31 August 2012 08:32 from flytomylife
Really thanks a lot.
13 September 2012 17:27 from Dave Stuart
Great article! I'm gonna use this as a reference.
19 September 2012 22:14 from Ahmet
really very useful. thanks for sharing ;)