A Complete Guide to the MVC 6 Tag Helpers


Tag Helpers are a new feature in MVC that you can use for generating HTML. The syntax looks like HTML (elements and attributes) but is processed by Razor on the server. Tag Helpers are in many ways an alternative syntax to Html Helper methods but they also provide some functionality that was either difficult or impossible to do with helper methods. Each tag helper has a different behavior and different options. This post will give you an overview and links to more details for each tag helper.

Adding Tag Helpers to Your Views

If you create a new MVC 6 project using Visual Studio then the built in MVC 6 tag helpers will be enabled automatically. You can add tag helpers from any other assembly/namespace by adding the @addTagHelper directive to your cshtml file.

@addTagHelper "*, Microsoft.AspNet.Mvc.TagHelpers"

To add tag helpers globally in your project, add the @addTagHelper directive to Views/_ViewImports.cshtml.

Link and Script Tag Helpers

The link and script tag helpers are intended to make it easier to add link and script tags to our HTML. In particular, these tag helpers simplify the process of referencing a large number of files in a development environment, referencing CDNs with local fallbacks and cache busting.

Let’s take a simple example where we want to include all the JS files in a particular folder:

We can do this easily with the Script tag helper by including all the files using a glob pattern:

<script asp-src-include="~/app/**/*.js"></script>

Which will generate the following HTML when a users visits the page:

<script src="/app/app.js"></script>
<script src="/app/controllers/controller1.js"></script>
<script src="/app/controllers/controller2.js"></script>
<script src="/app/controllers/controller3.js"></script>
<script src="/app/controllers/controller4.js"></script>
<script src="/app/services/service1.js"></script>
<script src="/app/services/service2.js"></script>

Learn more about referencing CDNs and Cache Busing with the Link and Script Tag Helpers

Environment Tag Helper

The Environment Tag Helper is used (typically in conjunction with the Link and Script Tag Helpers) to render different HTML in a developer vs. test vs. production environment.

Use this tag helper by wrapping any section of CSHTML and specifying which environments that section should be included in. Here is a simple example where we include individual CSS files in development, but a single combined / minified version in Staging and Production:

<environment names="Development">            
    <link rel="stylesheet" href="~/css/site1.css" />
    <link rel="stylesheet" href="~/css/site2.css" />
</environment>
<environment names="Staging,Production">
    <link rel="stylesheet" href="~/css/site.min.css" asp-file-version="true"/>
</environment>In the Development environment

In the Development environment, the following HTML would be sent to the browser:

<link rel="stylesheet" href="/css/site1.css" />
<link rel="stylesheet" href="/css/site2.css" />

In Staging and Production, the HTML would look like this:

<link rel="stylesheet" href="/css/site.min.css?v=UdxKHVNJA5vb1EsG9O9uURFDfEE3j1E3DgwL6NiDGMc"/>

Note that the Environment tag itself is never sent to the browser. The Environment value is set by setting the value of the ASPNET_ENV environment variable.

Learn more about Web Optimization in MVC 6 using the Environment Tag Helper.

Form Tag Helpers

This is an area where Tag Helpers really shine. It is my opinion that Tag Helpers can help you to create much cleaner cshtml for your forms than using the traditional HTML helper methods.

A very simple example is a basic text input. Here is a side by side comparison of creating a text box for the UserName property of your model:

<!--Create an input with additional class for UserName using Html Helper-->
@Html.EditorFor(l => l.UserName, new { htmlAttributes = new { @class = "form-control" } })

<!--Create an input with additional class for UserName using Tag Helper-->
<input asp-for="UserName" class="form-control" />

Both will generate identical HTML based on the attributes of the UserName property. The Tag Helper approach allows us to easily add HTML attributes to the input tag and those will be included in the generated HTML. Adding the form-control class is natural and easy to understand. By comparison, the @Html.EditorFor approach is clumsy and hard to read.

And in case you are wondering; Yes, you do get Intellisense just like you did with the helper methods:

image

Generating HTML for the form element is also much cleaner since you no longer need to mess around with a using statement to generate the closing form tag. All you need to do is specify the controller and action for the form:

<form asp-controller="Account" 
      asp-action="Login">
//Your form elements here
</form>

Which will generate the following HTML:

<form action="/Account/Login" method="post">
 
//Your form elements here
 
    <input name="__RequestVerificationToken" type="hidden" value="CfDJ8AFtmUdx-b5MkQvAyGYbjFmMGSMv0Fmk7gG4RqGXlkNV6yqKqj6fgq<n>nOh4TLT6ZnWSaqtAbKkgpEB20lvfkc2iOKZKIqt3tJ4Jij8DjmatTrZo-DKVOLwwOzj3kB8VKpFwc0rQMjaJTTC_gVv5f0vAg"</n>>
</form>

By default, it will create the anti-forgery token for you (I really like this feature), but you can turn it off if you want. Learn more about all the options for the Form Tag Helper.

There is a whole set of tag helpers related to creating form elements. You can learn more about them in great detail by following these links:

Anchor Tag Helper

This tag helper is an alternative to using @Html.ActionLink or @Url.Action helper methods. For example, the following code in a Razor view:

@Html.ActionLink("Register", "Register", "Account")
<a href="@Url.Action("Register","Account")">Register</a>

…would generate 2 identical anchor html tags.

<a href="/Account/Register">Register</a>
<a href="/Account/Register">Register</a>

Using the anchor tag helper, you can generate the same HTML as above by adding the asp-controller and asp-action attributes to an anchor tag as follows:

<a asp-controller="Account"      asp-action="Register">Register</a>

Learn more about options for the Anchor Tag Helper.

Cache Tag Helper

The Cache Tag Helper very unique and one of my favorite MVC 6 tag helpers. It allows you to wrap arbitrary cshtml code and it will cache the output of that cshtml in memory based on the parameters you specify. It is extremely easy to use yet provides a very powerful caching mechanism.

Take the following simple example:

<cache expires-after="@TimeSpan.FromMinutes(10)">
    @Html.Partial("_WhatsNew")
    *last updated  @DateTime.Now.ToLongTimeString()
</cache>

The Cache tag will not be included in the generated HTML. It is purely a server side tag. In the example above, only the results of the WhatsNew partial view and the *last updated text would be sent to the browser. Any subsequent requests within the 10 minute span simply return the cached contents instead of calling the partial view again. On the first request after the 10 minutes has passed, the contents would be regenerated and cached again for another 10 minutes.

There are a huge number of options for how when / how to expire the cached contents. Learn more about the Cache Tag Helper.

Image Tag Helper

The Image Tag Helper is a simple tag helper that allows you to aggressively cache images on the client side. While this is a very simple tag helper, it has special meaning for me. Implementing this tag helper was my first pull request submitted to the aspnet/mvc repo. Learn more about the Image Tag Helper.

Creating Your Own Tag Helpers

That covers all the tag helpers that are built in to MVC 6. It is also very easy to build your own tag helpers. For example, I created one that makes it much easier to use the Bootstrap progress bar control. You use this custom tag helper adding a bs-progress-value attribute on a div element:

<div bs-progress-value="@Model.PercentComplete"></div>

The custom tag helper takes care of building the slightly convoluted markup that Bootstrap requires to render the progress bar.

<div class="progress">
  <div class="progress-bar" role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100" style="width: 60%;">
    <span class="sr-only">60% Complete</span>
  </div>
</div>

To implement the custom tag helper, you need to inherit from the TagHelper class and override the Process method.

[TargetElement("div", Attributes = ProgressValueAttributeName)]
public class ProgressBarTagHelper : TagHelper
{
    private const string ProgressValueAttributeName = "bs-progress-value";
    private const string ProgressMinAttributeName = "bs-progress-min";
    private const string ProgressMaxAttributeName = "bs-progress-max";
    
    /// <summary>
    /// An expression to be evaluated against the current model.
    /// </summary>
    [HtmlAttributeName(ProgressValueAttributeName)]
    public int ProgressValue { get; set; }

    [HtmlAttributeName(ProgressMinAttributeName)]
    public int ProgressMin { get; set; } = 0;

    [HtmlAttributeName(ProgressMaxAttributeName)]
    public int ProgressMax { get; set; } = 100;

    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        var progressTotal = ProgressMax - ProgressMin;

        var progressPercentage = Math.Round(((decimal) (ProgressValue - ProgressMin) / (decimal) progressTotal) * 100, 4);

        string progressBarContent =
            string.Format(
@"<div class='progress-bar' role='progressbar' aria-valuenow='{0}' aria-valuemin='{1}' aria-valuemax='{2}' style='width: {3}%;'> 
<span class='sr-only'>{3}% Complete</span>
</div>", ProgressValue, ProgressMin, ProgressMax, progressPercentage);

        output.Content.Append(progressBarContent);

        string classValue;
        if (output.Attributes.ContainsKey("class"))
        {
            classValue = string.Format("{0} {1}", output.Attributes["class"], "progress");
        }
        else
        {
            classValue = "progress";
        }
        
        output.Attributes["class"] = classValue;
    }
}

See the full example of creating a custom tag helpers here.

Wrapping it up

That should cover pretty much everything you need to know about MVC 6 Tag Helpers. The concept might seem a little strange at first but this is something you should definitely try. The highlighting in Visual Studio makes it very obvious when an element will be processed by a tag helper and Intellisense provides a great experience when binding to properties of your model.

Comments (5)

  1. Abdul Rauf says:

    Nicely explained.

  2. Kiko says:

    Any suggestion on porting the environment tag helper to MVC5?

  3. Kiko, MVC doesn’t have tag helpers or any concept of them. It is a new thing for MVC 6. Your only option is to read the Web.config settings and having different settings per environment.

  4. Dfuster says:

    Very good explanation.
    I wonder if you know how can I access a specific cache tag helper outside the view. I mean, suppose I’m caching a specific part of the view, this part of the view needs to retrieve values from the database (if it were not cached). I need to know if that specific cache has not expired, and therefore I don’t need to call to the database. I need to make such decision inside the controller that renders the view, but I cannot find an answer to this. Is it possible to access certain cache tag helper stuff inside controllers?
    Thank you very much.

Skip to main content