Tag Helpers in ASP.NET Core
TLDR; In this post, we explore tag helpers, used in web applications using ASP.NET Core. They enable server-side C# code to create and render HTML elements in razor files. We look at some examples of tag helpers and their uses, and learn how to create custom tag helpers.
What are Tag Helpers and why are they used?
In ASP.NET Core web applications, whether using Razor Pages or MVC, the view pages, responsible for creating and rendering the HTML that will be used by the browser to display the requested page, are razor files. These are the files with the .cshtml extension and contain client and server side code. When this code is executed, it will result in HTML being sent to the browser.
The code inside of razor files has two particularities. One is that it uses razor syntax, which allows us to insert C# code inside of HTML. Usually, these bits of C# code will introduce bits of logic or data that we get from the controller or the model (in an MVC web application). The second particularity, and the subject of this blog post, is the use of tag helpers. These enable server-side C# code to create and render HTML elements in razor files. Tag helpers make razor files much more readable and easier to code.
In order to use tag helpers in an application, we must make them available in our application by adding them with the @addTagHelper
directive to our _ViewImports.cshtml
file in the Views folder:
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
A concrete example: creating forms in ASP.NET Core MVC
One very common place to use tag helpers is in forms. ASP.NET Core has a number of built-in tag helpers that allow us to work with forms. To illustrate how tag helpers are used and why they are useful and simplify our HTML code significantly, we will create a basic form in a web application using ASP.NET Core MVC. The form asks the user to input a username, email address, and password in order to subscribe to the site. In our Models folder, we have a Subscriber
class, used as the model in our Subscribe view page here.
Let's see what the Subscribe.cshtml view page looks like:
@model Subscriber
<form asp-action="Subscribe" method="post" class="form-horizontal" role="form">
<h4>Enter your details in order to subscribe.</h4>
<div class="form-group">
<label asp-for="Username" class="col-md-2 control-label"></label>
<div class="col-md-5">
<input asp-for="Username" class="form-control" />
<span asp-validation-for="Username" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<label asp-for="Email" class="col-md-2 control-label"></label>
<div class="col-md-5">
<input asp-for="Email" class="form-control" />
<span asp-validation-for="Email" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<label asp-for="Password" class="col-md-2 control-label"></label>
<div class="col-md-5">
<input asp-for="Password" class="form-control" />
<span asp-validation-for="Password" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-5">
<input type="submit" class="btn btn-primary" value="Subscribe" />
</div>
</div>
</form>
This renders the following view:
Let's look at some tag helpers used in this Subscribe view.
Form tag helper
The form tag helper will allow us to create forms. It will create the <form action="" />
attribute in the HTML code rendered in the browser, which, in an MVC web application, specifies the controller action used. To specify the controller action we want to target using tag helpers, we use the asp-action
attribute. Here, we are targeting the Subscribe
action in our SubscriberController.
In our code above, the following line
<form asp-action="Subscribe" method="post" class="form-horizontal" role="form">
will generate the following HTML:
<form method="post" class="form-horizontal" role="form" action="/Subscriber/Subscribe">
Other attributes that can be used on the form tag are:
- The
asp-controller
tag helper can be used to indicate which controller should be targeted by the post action of a form. - The
asp-route-*
tag helper (where * can be replaced with the name of the parameter we want to specify the value for) allows us to create a route. - The
asp-route
tag helper allows us to indicate which main route we want to use. - The
asp-forgery
tag helper allows us to prevent cross-site request forgery attacks on the site when used with the [ValidateAntiForgeryToken] attribute in the HTTP Post action method.
Label tag helper
Probably the most basic tag helper, the label tag helper is used to create a label for a property on our model object. It has only one attribute, asp-for
, used to indicate which property the label tag helper should be working with. This will display the name of the property we want to display.
In our code above, the following line
<label asp-for="Username" class="col-md-2 control-label"></label>
will generate the following HTML:
<label class="col-md-2 control-label" for="Username">Username</label>
We can see that the name of the generated for
attribute matches the name of the property we passed into the asp-for
tag helper. This is because the content of the label displays the name of the property. If we wanted to override this behaviour, we can add a different name in our razor code:
<label asp-for="Username" class="col-md-2 control-label">Different name</label>
And the following HTML is generated, overriding the label caption:
<label class="col-md-2 control-label" for="Username">Different name</label>
Input tag helper
The input tag helper is used to generate the corresponding HTML type, name, and id attributes based on the model property to which it is bound, determined by the asp-for
attribute.
In our code above, the following line
<input asp-for="Username" class="form-control" />
will generate the following HTML:
<input class="form-control" type="text" data-val="true" data-val-length="Must be between 5 and 80 characters" data-val-length-max="80" data-val-length-min="5" data-val-required="Username is required" id="Username" maxlength="80" name="Username" value="" />
The attribute type will change according to the .NET data type or Data Annotation attribute applied to the model, such as [DataType(DataType.EmailAddress)]
or [DataType(DataType.Password)]
.
Notice also the validation attributes generated. They are the data-val-*
attributes and contain validation information based on the .NET data type and the data annotations in our model property.
Validation tag helper
When performing validation checks on the user input, the ModelState
object will contain the error messages generated after the validation has been carried out. Validation tag helpers allow us to display these error messages in the view. In our razor code, above, we are using the asp-validation-for
tag helper, known as the “validation message” tag helper. This will display the validation message for the property specified.
In our code above, the following line
<span asp-validation-for="Username" class="text-danger"></span>
will generate the following HTML:
<span class="text-danger field-validation-valid" data-valmsg-for="Username" data-valmsg-replace="true"></span>
How to create a custom Tag Helper
As we have seen, tag helpers contain pieces of functionality that we can reuse very easily. One useful thing to do, if there is a bit of functionality in our application that we might be reusing more than once (and if a built-in tag helper doesn't exist for it) is to create our own custom tag helper. Let's look at a an example of how to do this.
We will build a tag helper that will render HTML that generates a link that allows the user to send an email to the owner of the web application we have created.
First, we need to make any custom tag helpers we create accessible to the rest of the application. Just like before, we use the @addTagHelper
directive in our _ViewImports.cshtml file in the Views folder. If our project is called MVCWebAppExample
and we create a folder called TagHelpers
in our project, where we will store all our custom tag helpers, we would add the following line of code:
@addTagHelper MVCWebAppExample.TagHelpers.*, MVCWebAppExample
We now create a new class called EmailTagHelper
that inherits from the TagHelper
base class. Naming conventions are important when creating applications using ASP.NET Core MVC, and this is no exception. By default, custom tag helpers will be usable by the name given before the “TagHelper” suffix, in this case, “email”.
Our TagHelper is going to accept an Address property - the email address that we are going to send the email to. By overriding the Process()
method, we will build the output - the HTML that we want to generate when our tag helper is used. The output is going to be an anchor tag, and the attribute href
is set to mailto:
with the specified email address as the value. href
is the attribute in HTML that specifies the URL of the page the link goes to.
public class EmailTagHelper : TagHelper
{
public string Address { get; set; }
public override void Process(TagHelperContext context, TagHelperOutput output)
{
output.TagName = "a";
output.Attributes.SetAttribute("href", "mailto:" + Address);
}
}
Let's now try to use it in our view page. If we create a Contact view page (and its corresponding controller), we can use our email tag helper, passing in the email address we want the email to be sent to.
Our Contact view page looks like this:
<h3>
Please use the button below to contact us.
</h3>
<email address="info@@taghelperexample.com">Contact us</email>
The HTML generated is the following:
<h3>Please use the button below to contact us.</h3>
<a href="mailto:info@taghelperexample.com">Contact us</a>
And the link to send the email shows in our Contact page
Conclusion
In this post, we have defined tag helpers, seen some examples, and learned how to build a very simple custom tag helper. We have seen the HTML code generated by tag helpers, which helps understand that using them makes our code more easily readable. This is especially visible with examples such as the validation tag helpers. It is worth paying a visit to the documentation for tag helpers to see further examples.