202

I'm trying to add a class to an input.

This is not working:

@Html.EditorFor(x => x.Created, new { @class = "date" })
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
user137348
  • 10,166
  • 18
  • 69
  • 89
  • 1
    NOTE: For some of the answers, even if they are correct, one may have to clear the browser cache for it to be actualized. This is especially true if the solution is css based or involves a css class! Just spent quite a while realizing that with a slightly different issue.... – JosephDoggie Feb 19 '15 at 18:00

16 Answers16

190

Adding a class to Html.EditorFor doesn't make sense as inside its template you could have many different tags. So you need to assign the class inside the editor template:

@Html.EditorFor(x => x.Created)

and in the custom template:

<div>
    @Html.TextBoxForModel(x => x.Created, new { @class = "date" })
</div>
Jess
  • 23,901
  • 21
  • 124
  • 145
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • 6
    This works great, thanks. Having trouble formatting the field value per the DisplayFormat annotation in my model. Formatted as annotated with EditorFor and DisplayFor, but not TextBoxFor :( Looks like I must use a custom template, unless someone can point me to something I'm missing. ? – Sean Dec 25 '11 at 17:53
  • 1
    Having the same problem where TextBoxFor doesn't honor the DisplayFormat set. – jocull Nov 29 '12 at 20:50
  • 4
    i have same issue, but i can't use TextBoxFor as i need DisplayFormat, which works with Editor or Display, but at the same time i need class too, so that i can display text in readonly form – A.T. Nov 09 '13 at 05:26
176

As of ASP.NET MVC 5.1, adding a class to an EditorFor is possible (the original question specified ASP.NET MVC 3, and the accepted answer is still the best with that considered).

@Html.EditorFor(x=> x.MyProperty,
    new { htmlAttributes = new { @class = "MyCssClass" } })

See: What's New in ASP.NET MVC 5.1, Bootstrap support for editor templates

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
EF0
  • 2,940
  • 4
  • 17
  • 23
  • 1
    During MVC 2,3,4 I didn't make sense... but as more people started to use and complain about lack of it - It suddenly made in sense in MVC 5 :D +1 – Piotr Kula Feb 01 '17 at 19:49
107

You can't set class for the generic EditorFor. If you know the editor that you want, you can use it straight away, there you can set the class. You don't need to build any custom templates.

@Html.TextBoxFor(x => x.Created, new { @class = "date" }) 
TuomasK
  • 1,849
  • 3
  • 13
  • 19
48

You can use:

@Html.EditorFor(x => x.Created, new { htmlAttributes = new { @class = "date" } })

(At least with ASP.NET MVC 5, but I do not know how that was with ASP.NET MVC 3.)

przno
  • 3,476
  • 4
  • 31
  • 45
28

I had the same frustrating issue, and I didn't want to create an EditorTemplate that applied to all DateTime values (there were times in my UI where I wanted to display the time and not a jQuery UI drop-down calendar). In my research, the root issues I came across were:

  • The standard TextBoxFor helper allowed me to apply a custom class of "date-picker" to render the unobtrusive jQuery UI calender, but TextBoxFor wouldn't format a DateTime without the time, therefore causing the calendar rendering to fail.
  • The standard EditorFor would display the DateTime as a formatted string (when decorated with the proper attributes such as [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:dd/MM/yyyy}")], but it wouldn't allow me to apply the custom "date-picker" class.

Therefore, I created custom HtmlHelper class that has the following benefits:

  • The method automatically converts the DateTime into the ShortDateString needed by the jQuery calendar (jQuery will fail if the time is present).
  • By default, the helper will apply the required htmlAttributes to display a jQuery calendar, but they can be overridden if needs be.
  • If the date is null, ASP.NET MVC will put a date of 1/1/0001 as a value.

This method replaces that with an empty string.

public static MvcHtmlString CalenderTextBoxFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes = null)
{
    var mvcHtmlString = System.Web.Mvc.Html.InputExtensions.TextBoxFor(htmlHelper, expression, htmlAttributes ?? new { @class = "text-box single-line date-picker" });
    var xDoc = XDocument.Parse(mvcHtmlString.ToHtmlString());
    var xElement = xDoc.Element("input");
    if (xElement != null)
    {
        var valueAttribute = xElement.Attribute("value");
        if (valueAttribute != null)
        {
            valueAttribute.Value = DateTime.Parse(valueAttribute.Value).ToShortDateString();
            if (valueAttribute.Value == "1/1/0001")
                valueAttribute.Value = string.Empty;
        }
    }
    return new MvcHtmlString(xDoc.ToString());
}

And for those that want to know the JQuery syntax that looks for objects with the date-picker class decoration to then render the calendar, here it is:

$(document).ready(function () {
    $('.date-picker').datepicker({ inline: true, maxDate: 0, changeMonth: true, changeYear: true });
    $('.date-picker').datepicker('option', 'showAnim', 'slideDown');
});
Adam Plocher
  • 13,994
  • 6
  • 46
  • 79
bigmac
  • 2,553
  • 6
  • 38
  • 61
  • That helped me just now, little issue with it - you need to check to make sure the valueAttribute.Value isnt empty or whitespace before passing it to the DateTime.Parse method, otherwise you risk a FormatException being thrown on an empty field. –  Mar 03 '12 at 22:16
  • This helped me, however if you're implementing this and you're expecting the field to perform validation you will need to apply this logic: http://stackoverflow.com/questions/12023970/mvc3-passing-incorrectly-formatted-datetime-to-controller-but-correcting-it-in-t – Aaron Newton Apr 18 '13 at 23:47
  • Good job, but did you know you can control if a DateTime or just a Date control appears just by using `DateTimePickerFor` and updating the model's date field you are representing with `[DataType(DataType.Date)]` or `[DataType(DataType.DateTime)]`? You can also put it into, say, mm/dd/yyyy form with `.ParseFormats(new string[] { "MM/dd/yyyy" })` (or modify it to whatever you want, easily). If it's null, the field does render as empty without having to code that in. – vapcguy Oct 30 '14 at 05:14
  • Razor won't recognize `@MyHtmlHelpers.CalenderTextBoxFor(model => model.ExpirationDate)`. Any ideas on how to implement this ? – Mehdiway Jan 19 '16 at 11:32
17

It is possible to provide a class or other information through AdditionalViewData - I use this where I'm allowing a user to create a form based on database fields (propertyName, editorType, and editorClass).

Based on your initial example:

@Html.EditorFor(x => x.Created, new { cssClass = "date" })

and in the custom template:

<div>
    @Html.TextBoxFor(x => x.Created, new { @class = ViewData["cssClass"] })
</div>
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Brett
  • 171
  • 1
  • 2
  • 8
    @Html.EditorFor(x => x.Created,new { cssClass = "date" }) did not work for me – Alan Macdonald Jul 22 '13 at 10:11
  • 2
    This worked for me & is a better answer than the one marked. It provides the benefit of using a template, yet allowing for some customization without jQuery hacks. – Chad Hedgcock Mar 11 '14 at 16:43
  • TextBoxFor ignores other attributes one may set in the model, like 'DataType's for example. – Markus Apr 09 '15 at 16:36
8

There isn't any EditorFor override that lets you pass in an anonymous object whose properties would somehow get added as attributes on some tag, especially for the built-in editor templates. You would need to write your own custom editor template and pass the value you want as additional viewdata.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
marcind
  • 52,944
  • 13
  • 125
  • 111
2

Using jQuery, you can do it easily:

$("input").addClass("class-name")

Here is your input tag

@Html.EditorFor(model => model.Name)

For DropDownlist you can use this one:

$("select").addClass("class-name")

For Dropdownlist:

@Html.DropDownlistFor(model=>model.Name)
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Praveen M P
  • 11,314
  • 7
  • 34
  • 41
2
@Html.EditorFor(m=>m.Created ...) 

does not allow any arguments to be passed in for the Text box

This is how you can apply attributes.

@Html.TextBoxFor(m=>m.Created, new { @class= "date", Name ="myName", id="myId" })
Jayant Varshney
  • 1,765
  • 1
  • 25
  • 42
2

While the question was targeted at MVC 3.0, we find the problem persists in MVC 4.0 as well. MVC 5.0 now includes natively an overload for htmlAttributes.

I am forced to use MVC 4.0 at my current place of employment and needed to add a css class for JQuery integration. I solved this problem using a single extension method...

Extension Method:

using System.Linq;
using System.Web.Mvc;
using System.Web.Routing;
using System.Xml.Linq;

namespace MyTest.Utilities
{
    public static class MVCHelperExtensionMethods
    {
        public static MvcHtmlString AddHtmlAttributes(this MvcHtmlString input, object htmlAttributes)
        {
            // WE WANT TO INJECT INTO AN EXISTING ELEMENT.  IF THE ATTRIBUTE ALREADY EXISTS, ADD TO IT, OTHERWISE
            // CREATE THE ATTRIBUTE WITH DATA VALUES.

            // USE XML PARSER TO PARSE HTML ELEMENT
            var xdoc = XDocument.Parse(input.ToHtmlString());
            var rootElement = (from e in xdoc.Elements() select e).FirstOrDefault();

            // IF WE CANNOT PARSE THE INPUT USING XDocument THEN RETURN THE ORIGINAL UNMODIFIED.
            if (rootElement == null)
            {
                return input;
            }

            // USE RouteValueDictionary TO PARSE THE NEW HTML ATTRIBUTES
            var routeValueDictionary = new RouteValueDictionary(htmlAttributes);

            foreach (var routeValue in routeValueDictionary)
            {
                var attribute = rootElement.Attribute(routeValue.Key);

                if (attribute == null)
                {
                    attribute = new XAttribute(name: routeValue.Key, value: routeValue.Value);
                    rootElement.Add(attribute);
                }
                else
                {
                    attribute.Value = string.Format("{0} {1}", attribute.Value, routeValue.Value).Trim();
                }
            }

            var elementString = rootElement.ToString();
            var response = new MvcHtmlString(elementString);
            return response;
        }
    }
}

HTML Markup Usage:

@Html.EditorFor(expression: x => x.MyTestProperty).AddHtmlAttributes(new { @class = "form-control" })

(Make sure to include the extension method's namespace in the razor view)

Explanation: The idea is to inject into the existing HTML. I opted to parse the current element using Linq-to-XML using XDocument.Parse(). I pass the htmlAttributes as type object. I utilize MVC RouteValueDictionary to parse the htmlAttributes passed in. I merge the attributes where they already exist, or add a new attribute if it does not yet exist.

In the event the input is not parsable by XDocument.Parse() I abandon all hope and return the original input string.

Now I can use the benefit of the DisplayFor (rendering datatypes such as currency appropriately) but also have the ability to specify css classes (and any other attribute for that matter). Could be helpful for adding attributes such as data-*, or ng-* (Angular).

barrypicker
  • 9,740
  • 11
  • 65
  • 79
1

You can create the same behavior creating a simple custom editor called DateTime.cshtml, saving it in Views/Shared/EditorTemplates

@model DateTime

@{
    var css = ViewData["class"] ?? "";
    @Html.TextBox("", (Model != DateTime.MinValue? Model.ToString("dd/MM/yyyy") : string.Empty), new { @class = "calendar medium " + css});
}

and in your views

@Html.EditorFor(model => model.StartDate, new { @class = "required" })

Note that in my example I'm hard-coding two css classes and the date format. You can, of course, change that. You also can do the same with others html attributes, like readonly, disabled, etc.

Alexandre
  • 389
  • 3
  • 8
1

I used another solution using CSS attribute selectors to get what you need.

Indicate the HTML attribute you know and put in the relative style you want.

Like below:

input[type="date"]
{
     width: 150px;
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
1

No need to create custom template for MVC 4. Use TextBox instead of EditFor here special html attributes are not supported, it is only supported from MVC 5. TextBox is should support for MVC 4, I don't know about other version.

@Html.TextBox("test", "", new { @id = "signupform", @class = "form-control", @role = "form",@placeholder="Name" })
Merbin Jo
  • 1,189
  • 1
  • 11
  • 19
0

You could also do it via jQuery:

$('#x_Created').addClass(date);
Scott R. Frost
  • 2,026
  • 1
  • 22
  • 25
0

I just needed to set the size of one textbox on one page. Coding attributes on the model and creating custom editor templates were overkill, so I just wrapped the @Html.EditorFor call with a span tag that called a class which specifies the size of the textbox.

CSS class declaration:

.SpaceAvailableSearch input
{
    width:25px;
}

View code:

<span class="SpaceAvailableSearch">@Html.EditorFor(model => model.SearchForm.SpaceAvailable)</span>
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Earl
  • 89
  • 1
  • 4
0

One Best way to apply class to @Html.EditorFor() in MVC3 RAzor is

@Html.EditorFor(x => x.Created)


<style type="text/css">

#Created
{
    background: #EEE linear-gradient(#EEE,#EEE);   
    border: 1px solid #adadad;
    width:90%;
    }
</style>

It will add above style to your EditorFor()

It works for MVC3.

Bilal
  • 41
  • 3