Learn how display and editor templates let you decide once how a type such as a date, a price or an address should look, and then reuse that decision on every page with DisplayFor and EditorFor.

Bishal Biswas
Self Learner
Decide once, reuse everywhere
Imagine your app shows prices in twenty different views. One day the designer asks you to show them in green with a currency symbol. You now have twenty files to edit.
A display template solves this. It is a tiny view that says “this is how a value of this type should look”. Once you write it, Html.DisplayFor() uses it automatically wherever that type appears.
An editor template does the same job for input fields. Write one editor template for DateTime and every date field in your app gets the same date picker.
The two helper methods
These helpers were introduced in the HTML helpers topic. Here is what they do again in one line each:
@Html.DisplayFor(m => m.Price)
@Html.EditorFor(m => m.Price)
DisplayFor renders the value for reading. EditorFor renders an input for editing. Both look at the type of the property and pick a template.
Without any custom templates, they still work. A bool becomes a disabled checkbox in display mode and a live checkbox in edit mode. A string becomes plain text or a text box. These are the built in templates.
Where templates live
Templates are just .cshtml files placed in special folders:
Views/
Shared/
DisplayTemplates/
Decimal.cshtml
DateTime.cshtml
Address.cshtml
EditorTemplates/
DateTime.cshtml
Address.cshtml
The file name must match the type name of the value. Decimal.cshtml handles decimal, DateTime.cshtml handles DateTime, and Address.cshtml handles your own Address class.
You can also put the folders under a specific controller’s view folder, such as Views/Products/DisplayTemplates/, and those templates will only apply to that controller’s views.
Your first display template
Let us make every decimal show as money:
@* Views/Shared/DisplayTemplates/Decimal.cshtml *@
@model decimal
<span class="price">@Model.ToString("C")</span>
Now in any view:
<p>Price: @Html.DisplayFor(m => m.Price)</p>
<p>Price: <span class="price">$49.99</span></p>
Change the template and every price in the app changes with it.
A template for your own class
Templates shine with small classes that appear in many places. Here is an address:
public class Address
{
public string Street { get; set; } = "";
public string City { get; set; } = "";
public string PostalCode { get; set; } = "";
}
@* Views/Shared/DisplayTemplates/Address.cshtml *@
@model Address
<address>
@Model.Street<br />
@Model.City @Model.PostalCode
</address>
Use it wherever an Address shows up:
@model Order
<h2>Shipping to</h2>
@Html.DisplayFor(m => m.ShippingAddress)
<h2>Billing to</h2>
@Html.DisplayFor(m => m.BillingAddress)
Editor templates
An editor template renders inputs. The important rule is that the field names must line up with the model so that model binding works when the form is posted. asp-for handles this for you because it knows the current prefix:
@* Views/Shared/EditorTemplates/Address.cshtml *@
@model Address
<div class="mb-3">
<label asp-for="Street"></label>
<input asp-for="Street" class="form-control" />
</div>
<div class="mb-3">
<label asp-for="City"></label>
<input asp-for="City" class="form-control" />
</div>
<div class="mb-3">
<label asp-for="PostalCode"></label>
<input asp-for="PostalCode" class="form-control" />
</div>
When called with @Html.EditorFor(m => m.ShippingAddress), the inputs come out with names like ShippingAddress.Street. That is exactly what the binder needs to fill an Order object.
Templates for a whole collection
If the property is a List<Address>, DisplayFor renders the template once per item. You do not write a loop:
@model Customer
@Html.DisplayFor(m => m.Addresses)
Each item is rendered with the Address template, with correct indexed names like Addresses[0].Street in editor mode.
Choosing a template by name
Sometimes one type needs two looks. A DateTime might be a full date in one place and just the month elsewhere. Give the template a different file name and ask for it:
@* Views/Shared/DisplayTemplates/MonthOnly.cshtml *@
@model DateTime
@Model.ToString("MMMM yyyy")
@Html.DisplayFor(m => m.PublishedOn, "MonthOnly")
The second argument is the template name. You can also attach it to the model with [UIHint("MonthOnly")] so you never have to repeat the name in views.
DisplayForModel and EditorForModel
These two render the entire model using templates for each property:
@model Product
<dl>
@Html.DisplayForModel()
</dl>
<form asp-action="Create" method="post">
@Html.EditorForModel()
<button type="submit">Save</button>
</form>
They are quick for admin pages and prototypes. For public pages you usually want more control over layout, so you write the fields by hand.
Data annotations affect templates
Attributes on the model change what the built in templates produce:
public class Product
{
[Display(Name = "Product name")]
public string Name { get; set; } = "";
[DataType(DataType.Currency)]
public decimal Price { get; set; }
[DataType(DataType.MultilineText)]
public string Description { get; set; } = "";
[DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
public DateTime ReleaseDate { get; set; }
[HiddenInput]
public int Id { get; set; }
}
DataType.MultilineText gives a text area. DisplayFormat controls the string format. HiddenInput renders a hidden field in editor mode. These are all handled by the built in templates without any custom files.
Quick recap
- A display template decides how a type looks when read, and an editor template decides how it looks when edited.
- Put them in
Views/Shared/DisplayTemplatesandViews/Shared/EditorTemplates, named after the type. Html.DisplayForandHtml.EditorForpick the template automatically, including for lists.- Pass a template name or use
[UIHint]when one type needs more than one look. DisplayForModelandEditorForModelrender every property in one call.- Data annotations such as
[DataType]and[DisplayFormat]shape the built in templates without custom files.
// Models/Address.cs
public class Address
{
public string Street { get; set; } = "";
public string City { get; set; } = "";
public string PostalCode { get; set; } = "";
}
// Models/Order.cs
public class Order
{
public int Id { get; set; }
[Display(Name = "Order total")]
public decimal Total { get; set; }
[DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
public DateTime PlacedOn { get; set; }
[UIHint("MonthOnly")]
public DateTime ShipMonth { get; set; }
public Address ShippingAddress { get; set; } = new();
public Address BillingAddress { get; set; } = new();
}
// Views/Shared/DisplayTemplates/Decimal.cshtml
//
// @model decimal
// <span class="price">@Model.ToString("C")</span>
// Views/Shared/DisplayTemplates/MonthOnly.cshtml
//
// @model DateTime
// @Model.ToString("MMMM yyyy")
// Views/Shared/DisplayTemplates/Address.cshtml
//
// @model Address
// <address>@Model.Street<br />@Model.City @Model.PostalCode</address>
// Views/Shared/EditorTemplates/Address.cshtml
//
// @model Address
// <input asp-for="Street" class="form-control" placeholder="Street" />
// <input asp-for="City" class="form-control" placeholder="City" />
// <input asp-for="PostalCode" class="form-control" placeholder="Postal code" />
// Views/Orders/Details.cshtml
//
// @model Order
// <p>Total: @Html.DisplayFor(m => m.Total)</p>
// <p>Ships: @Html.DisplayFor(m => m.ShipMonth)</p>
// @Html.DisplayFor(m => m.ShippingAddress)
// Views/Orders/Edit.cshtml
//
// @model Order
// <form asp-action="Edit" method="post">
// <input type="hidden" asp-for="Id" />
// <h3>Shipping</h3>
// @Html.EditorFor(m => m.ShippingAddress)
// <h3>Billing</h3>
// @Html.EditorFor(m => m.BillingAddress)
// <button type="submit">Save</button>
// </form>
Was this explanation helpful?
Your feedback helps us improve the content for everyone.
Thank you for your feedback!
We appreciate you helping us improve.
What could we improve? (Optional)
Read aloud
Ready