HTML Helpers For Forms In Razor Web Pages

A nugget that has remained partially hidden from view within the Web Pages framework is the HtmlHelper class. Parts of this class peek out in the template sites provided in WebMatrix where validation is performed and related messages displayed, but a vast range of methods designed for rendering form inputs are often overlooked in tutorials, blog articles and books (mine included). This article provides an overview of Web Pages HTML Helpers, and digs into one or two in more detail.

There are HTML helpers for every kind of form control: check boxes, hidden fields, password boxes, radio buttons, text boxes, text areas, dropdown lists and list boxes. There is also a helper for the HTML Label element, which associates descriptive text to a form control and can provide usability improvements in certain cases. Each helper method provides a shorthand way to render valid HTML for the specific control. The following table lists the Html Helpers and maps them to their HTML counterpart:

Helper HTML Element
Html.CheckBox <input type="checkbox" />
Html.DropDownList <select></select>
Html.Hidden <input type="hidden" />
Html.Label <label for="" />
Html.ListBox <select></select> or <select multiple></select>
Html.Password <input type="password" />
Html.Radio <input type="radio" />
Html.TextArea <textarea></textarea>
Html.TextBox <input type="text" />


If you have had any exposure to ASP.NET MVC, these helpers will look familiar. However, don't be fooled - the Web Pages helpers do not always work in the same way as their MVC counterparts. For one thing, there is no concept of "model binding" in ASP.NET Web Pages (yet). For another, some of the overloads do not map to an MVC counterpart.

Most of the Web Pages HTML Helpers work in the same way to MVC, and have a similar set of overloads. The TextBox helper is a good example for illustrating the basics. Here's a list of the overloaded methods:

TextBox(String, Object)
TextBox(String, Object, IDictionary<String, Object>)
TextBox(String, Object, Object)

The first method generates an HTML text input with a name and id attribute that uses the string value passed to the method. The second does the same, but allows you to specify the value of the text box through the object parameter. The third and fourth options build on the second, but offer two different ways to pass values for other attributes (width, style, class etc) either as a dictionary, or as an anonymous object. Here's a form that illustrates how these work:

<form method="post">
    First Name: @Html.TextBox("firstname")<br />
    Last Name: @Html.TextBox("lastname", Request["lastname"])<br />
    Town: @Html.TextBox("town", Request["town"], new Dictionary<string, object>(){{ "class", "special" }})<br />
    Country: @Html.TextBox("country", Request["country"], new { size = 50 })<br /> 
    <input type="submit" />

And here's the HTML source for the rendered page:

<form method="post">
    First Name: <input id="firstname" name="firstname" type="text" value="" /><br />
    Last Name: <input id="lastname" name="lastname" type="text" value="" /><br />
    Town: <input id="town" name="town" class="special" type="text" value="" /><br />
    Country: <input id="country" name="country" size="50" type="text" value="" /><br /> 
    <input type="submit" />

Most of the other helpers feature the same set of four overloaded methods - even the Hidden field where attributes other than id, name and value seem irrelevant. The Radio and CheckBox helpers feature additional overloads that have a Boolean parameter through which you can specifiy whether the input should be checked or not. The following line of code results in a checked checkbox with the name and id of "myCheck":

@Html.CheckBox("myCheck", true)

DropDownLists and ListBoxes are a different proposition.There are eight overloads for the DropDownList and twelve overloads for the ListBox helper. Eight of the ListBox overloads result in exactly the same HTML as the eight DropDownList helper methods - an HTML select element that allows single selection. The other four ListBox overloads accept a Boolean, which if set to true, allows multiple selections. All a bit odd and unnecessary, really. And for that reason, I would recommend that you use the DropDownList helper for single selection lists, and the ListBox only for multi-selection to save yourself confusion. Doing this will make transition to MVC (should you decide to go that route) a lot easer too, because MVC doesn't feature anywhere as many overloads for the ListBox.

All of the DropDownList and ListBox helpers expect an IEnumerable<SelectListItem> to be provided. A SelectListItem has three properties: Value, Text and Selected. The Value property is used by the HTML value attribute of an option element, and is the value passed in the Request collection when the form is submitted. The Text property is displayed on screen and the Selected property determines whether the the item should be preselected. The following code shows how to construct a List<SelectListItem>, setting two of the items as Selected, and then passing that to a ListBox which allows multiple selection:

    var items = new List<SelectListItem>{
        new SelectListItem {Value = "1", Text = "Blue"},
        new SelectListItem {Value = "2", Text = "Red"},
        new SelectListItem {Value = "3", Text = "Green", Selected = true},
        new SelectListItem {Value = "4", Text = "Yellow", Selected = true},
        new SelectListItem {Value = "5", Text = "Black"}
@Html.ListBox("myListbox", items, null, 6, true)  

The overloaded helper method used here is ListBox(String, IEnumerable(SelectListItem), Object, Int32, Boolean). The next example shows how to generate a IEnumerable<SelectListItem> from a database query. This time, the collection will feature in a DropDownList and only one of the items will be set as selected - the item with a CategoryId of 4:

    var db = Database.Open("Northwind");
    var data = db.Query("SELECT CategoryId, CategoryName FROM Categories");
    var items = data.Select(i => new SelectListItem {
        Value = i.CategoryId.ToString(), 
        Text = i.CategoryName,
        Selected = i.CategoryId == 4 ? true : false
@Html.DropDownList("CategoryId", items)

The code above uses LINQ To Objects to work on the collection returned from the Database.Query method call. You don't have to use LINQ To Objects. You could simply iterate the data variable in a foreach loop, and build a collection of SelectListItems that way, but LINQ is the new foreach loop.

The final example shows a DropDownList created from the overloaded method that has the most parameters:

    var db = Database.Open("Northwind");
    var data = db.Query("SELECT CategoryId, CategoryName FROM Categories");
    var items = data.Select(i => new SelectListItem {
        Value = i.CategoryId.ToString(), 
        Text = i.CategoryName
@Html.DropDownList("CategoryId", "Please Select One", items, 4, new {@class = "special"})

This is the same database query as in the previous example, except that none of the items have their Selected property set to true. That job is left to the helper instead. The first parameter provides a name attribute as usual, and the second sets the "default text". The fourth parameter represents the value of the selected item and the final parameter sets the CSS class of the select list to "special". Notice that when using an anonymous object to specify HTML attributes, you must prefix C# keywords used as property names with an @ sign (in this case "class"). This is nothing to do with Razor, but is part of the C# language specification.


Date Posted:
Last Updated:
Posted by:
Total Views to date: 121279


- Len Wright

Nicely done, Mike. Accidentally rate this as a 1 instead of 5. Silly iPad.

- anwarhaque

All control code are so good I try this code next project

- Justin Reeves

Hi Mike, I have your book which I found very useful in getting started with Web Pages. One thing that I couldn't get working was the "Selected" helper. I am dynamically creating a drop down with Month & Year combo, I was to retain the selection between posts but I don't seem to be able to apply the helper to a dynamically generated DDL. None of the above seem to address this unless I'm being dumb (which may be the case!). Any help appreciated! :)

- Mike


I recommend you post a question to a forum detailing what you have done so far.

- Robby

In this example you pass a IEnumerable parameter to the helper function. Is it possible to pass a recordset parameter to a helper function ?

- Mike


The DropDownList and ListBox helpers expect an IEnumerable. I'm not sure what you mean by "recordset" but I doubt if it meets that criteria, so the answer would be No.

- Parthiban K

It's was really use full website for mee..
surly it gonna rocking:))

- deltaecho5

I am new to Razor/MVC, having only dabbled in programming as a hobby off and on as part of a fascination with computers (from IBM 370's to now). BASIC was taught to me in the 10th grade, and since then I piddle here and there in an attempt to learn code languages -from Fortran to MPM, from APL to Turbo Pascal, from VB to Visual C++, from HTML/Java to ASP/PHP and now to MVC - to keep my brain sharp. It is indeed spaghetti in my brain.

I am far from an adequate coder, and am more dangerous than intelligent when it comes to attempting some silly site project or the like.

Over and over I search the web for solutions to what turn out to be incredibly obvious to veterans (eg. "what? You don't know that 'I' comes before 'E' except after 'C' you silly stupid old man? Stay off the internet!" LOL).

Over and over, in my quest to gain some simple knowledge that MS seems to invariably leave out of it's knowledge base or doesn't explain completely, I arrive at one of your blogs/posts/articles.

Once again - you showed me something that I searched for hours in order to complete something simple that had previously escaped me, and I wanted to thank you.

Your knowledge is welcome, and your ability to put concise and clear information into my brain keeps me bookmarking your information.

Thanks. I earned my gray hairs, but I am happy that reading things you write doesn't add to them.

Cheers Mike!

Add your comment

If you have any comments to make about this article, please use this form to do so. Make sure that your comment relates specifically to the article above. More general comments can be posted through the form on the Contact page.

Please note, all comments are moderated, and I end up deleting quite a lot. The kind of things that will ensure your comment is deleted without ever seeing the light of day are as follows:

  • Requests to fix your code (post a question to instead, please)
  • Gratuitous links to your own site or product
  • Anything abusive or libellous
  • Spam

I do not pass email addresses on to spammers, so a valid one will assist me in responding to you personally if required.

Recent Comments

hosein ey 2/25/2015 1:56 PM
In response to ASP.NET MVC 5 with EF 6 - Working With Files
tnx for this article do you think next version of entityframework support's the sql server and ?...

Saywer Ford 2/25/2015 5:15 AM
In response to Optimising ASP.NET Web Pages Sites - Bundling And Minification
Great Article. I did everything right and working fine. How about page specific js files. Lets I...

Saravanan 2/24/2015 10:54 AM
In response to Optimising ASP.NET Web Pages Sites - Bundling And Minification
Hi, Great article about the Bundling and minification. Regards the caching as you mentioned the...

Justin 2/24/2015 10:43 AM
In response to Scheduled Tasks In ASP.NET With Quartz.Net
I'm having the same problem as Ingmar. Everything is working fine locally in Visual Studio, but I it...

Logan Mudlo 2/23/2015 4:59 PM
In response to WebMatrix - A First Application
Is there a way to prevent the automatic close on a Database.Open() call?...

Mog0 2/23/2015 11:16 AM
In response to ASP.NET MVC 5 with EF 6 - Working With Files
Probably a silly question but why did you disable cascade delete and implement it yourself?...

Jose-Maria 2/19/2015 3:29 PM
In response to Migrating From Razor Web Pages To ASP.NET MVC 5 - Views and Controllers
Just great ! Many thanks Mike....

Satyabrata Mohapatra 2/19/2015 12:02 PM
In response to Migrating From Razor Web Pages To ASP.NET MVC 5 - Views and Controllers
This is great!!...

Ryan Helmoski 2/19/2015 10:24 AM
In response to Conversion of a datetime2 data type to a datetime data type resulted in an out-of-range value
Thank you!...

Harsha 2/19/2015 8:27 AM
In response to iTextSharp - Adding Text with Chunks, Phrases and Paragraphs
Hi, Can text area be created so that I can type text in the area in pdf document? We have Add text...