Search⌘ K
AI Features

What is a Tag Helper?

Explore how ASP.NET Core MVC uses tag helpers to extend HTML capabilities in Razor views. Understand the Razor parsing process, how tag helpers modify tags and attributes, and how to add them to pages using directives. This lesson equips you to implement and manage tag helpers for dynamic web applications.

Razor enriches HTML with new tags and attributes. It enables us to add our custom tags and attributes thanks to a feature called tag helpers.

In order to understand how the tag helpers feature works and how to take advantage of it, we need to understand how Razor parses the tags it finds in the code:

  1. It parses the open tag and stores the tag name and all attribute-value pairs contained in the tag in a data structure. When computing all values, it possibly computes C# expressions used to furnish dynamic values.
  2. It recursively parses the tag content until it finds the corresponding closure tag, thus building a tree whose nodes contain each, a tag with its attribute-value pairs, or simple text if the node represents a string content instead of a tag.
  3. It recursively transforms the tag content tree into an HTML string, and then it renders the open tag its attribute, its content, and finally the closure tag.

After point 2, we can add hooks that process the node data structure, possibly changing the tag name and or some tag attributes before Razor moves to point 3.

Suppose, for instance, that Razor is parsing the customized a tag below:

HTML
<a asp-controller="Products" asp-action="Index">Show products</a>

The above a tag receives controllers and action methods instead of an URL. How can we transform it into a valid HTML a tag with the appropriate URL in its href attribute?

It is enough to hook all a tags that have an asp-action attribute at point 2 of the Razor parsing algorithm and to do what follows:

  1. Take the values of the asp-controller and asp-action attributes in the a node, and use them to compute the URL that corresponds to the given controller and action method. If asp-controller is not provided, we may take the name of the controller that invoked the view.
  2. Replace the asp-controller and asp-action attributes with a usual href attribute containing the URL computed in the previous point.

After the above hook, the Razor parsing algorithm moves at point 3 thus rendering the modified tag node as:

HTML
<a href="<computed url>">Show products</a>

That’s all!

Defining parsing hooks with tag helpers

Tag helpers are C# classes inheriting from the framework TagHelper abstract class, which specifies each different hook for the Razor parsing algorithm. Each tag helper specifies both a hook condition and how to modify the original node. For example, the hook described in the previous example can be implemented with a single tag helper whose hook condition is: tag name must be a and tag must contain a non-empty asp-action attribute.

Since tag helpers modify an existing parsing node without changing its structure, several tag helpers can be chained one after the other on the same node. For this reason, tag helpers also specify a priority that is used for deciding their execution order.

Tag helpers may also enable tags to receive non-string attributes. For instance, we might define a display-customer tag that accepts a customer instance as the value of its asp-instance attribute:

HTML
<display-customer asp-instance = "myCustomer" >Show products</display-customer>

Non-string values are enclosed between quotes similar to usual HTML string attributes. This doesn’t confuse the parser because the type of all attributes is declared in the tag helper definition.

During Razor parsing of a tag, all available tag helpers whose hook conditions are met are sorted according to their priority and applied one after the other.

We will describe how to code a tag helper in a dedicated lesson. The remainder of this lesson explains how to make some tag helpers available to a Razor file.

Adding tag helpers to pages and views

Tag helpers can be added to pages and views with the @addTagHelper directive:

HTML
@model MyViewModel
@using MyNamespace
...
@addTagHelper {full name of tag helper type}, {name of tag helper assembly}

@addTagHelper needs the full name of the tag helper and the name of the assembly it is defined in. The assembly must be referenced by the project that contains the Razor file with the @addTagHelper directive.

While the name of the assembly is always obligatory, we may use a wildcard for the whole tag helper type name or for parts of it.

For example, consider the directive below:

HTML
@addTagHelper *, MyTagHelpersAssembly

It adds all tag helpers contained in the MyTagHelpersAssembly assembly.

Consider the directive below:

HTML
@addTagHelper MyNameSpace.*, MyTagHelpersAssembly

It adds all tag helpers contained in the MyTagHelpersAssembly assembly and whose namespace is MyNameSpace

Adding tag helpers to _ViewImports.cshtml

The @addTagHelper directive can also be added to the _ViewImports.cshtml file contained in the Views and Pages folders, in which case it applies to all views and pages. Below is the default _ViewImports.cshtml that is automatically filled when we create an ASP.NET Core MVC project:

HTML
@using MvcProject
@using MvcProject.Models
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

It automatically adds all tag helpers contained in the Microsoft.AspNetCore.Mvc.TagHelpers dll, which contains all ASP.NET Core out-of-the-box tag helpers. We will analyze most of them in the next lesson, and others in further lessons.

Since folders nested inside the Views and Pages folders can have their own _ViewImports.cshtml files, too, we can add different tag helpers to all Razor views and pages of different folders.

Moreover, in the _ViewImports.cshtml file of a nested folder, we may also remove some tag helpers added in the _ViewImports.cshtml file of a previous folder with the @removeTagHelper directive.

For instance, suppose that the _ViewImports.cshtml file in the Views folder contains the following directive:

HTML
@addTagHelper *, MyTagHelpersAssembly

We may remove some of MyTagHelpersAssembly tag helpers from all views contained in a subfolder of Views, say Products, by adding a _ViewImports.cshtml in Products with the following directive:

HTML
@removeTagHelper MyNameSpace.*, MyTagHelpersAssembly

The above directive removes all MyTagHelpersAssembly tag helpers whose namespace is MyNameSpace.

Choosing when to hook tag helpers

We can also decide to look for tag helper hooks on each specific tag invocation. For this purpose, we declare a tag helper prefix with the @tagHelperPrefix directive:

HTML
@tagHelperPrefix th:

After, the above declaration, tags must be prefixed with th: to enable tag helpers hooking. Thus, after that declaration the tag below stops being translated into a usual a tag:

HTML
<a asp-controller="Procucts" asp-action="Index">Show products</a>

tag helper hook application can be resumed by adding the th: prefix:

HTML
<th:a asp-controller="Products" asp-action="Index">Show products</th:a>

Tag helper hooks on a specific tag instance can also be disabled without a @tagHelperPrefix directive by prefixing the tag name with a !:

HTML
<!a asp-controller="Products" asp-action="Index">Show products</!a>

The above markup prevents the replacement of asp-controller and asp-action attributes with the appropriate href, so in the browser HTML sources we will find the untranslated markup below:

HTML
<a asp-controller="Products" asp-action="Index">Show products</a>