Creating Custom Tag Helper in ASP.NET Core MVC

Creating Custom Tag Helper in ASP.NET Core MVC

In this article, I will discuss Creating a Custom Tag Helper in the ASP.NET Core MVC Application with Examples. Please read our previous article discussing Partial Tag Helper in ASP.NET Core MVC Application.

Creating Custom Tag Helper in AS.NET Core MVC

Creating a custom Tag Helper in ASP.NET Core MVC allows you to extend the functionality of your HTML tags, making it easier to incorporate server-side logic directly within your views. This is useful for repetitive tasks, custom content generation, or when integrating complex UI elements that require backend data interaction.

How Do We Create a Custom Tag Helper Class?

The Custom Tag Helper in ASP.NET Core MVC is nothing but a class that implements the ITagHelper interface. However, ASP.NET Core MVC allows us to implement this interface with the TagHelper class. It’s a three-step process as follows:

  • Add a new class to your project
  • Inherit from TagHelper class. You need to include the namespace Microsoft.AspNetCore.Razor.TagHelpers.
  • Override the Process or ProcessAsync method.

So, to create a Custom Tag Helper in ASP.NET Core MVC, the first step is to create a class that inherits from the TagHelper class. This class provides a virtual method to generate HTML tags. It contains synchronous (Process) and asynchronous (ProcessAsync) implementation of the virtual method.

public virtual Task ProcessAsync(TagHelperContext context, TagHelperOutput output);
public virtual void Process(TagHelperContext context, TagHelperOutput output);

Based on our requirements, we need to override either one or both. The Process (or ProcessAsync) method is responsible for generating the HTML that the browser will render. It receives context object, i.e., TagHelperContext instance and TagHelperOutput instance, which we can use to read and change the content of our tag helper. If this is not clear at this moment, don’t worry; we will try to understand this with examples.

Example to Understand Tag Helper in ASP.NET Core MVC:

First, create a folder named TagHelpers inside the project root directory. This is where we will be creating our custom Tag Helpers.

In the next step, create a class file named MyCustomTagHelper inside the TagHelpers folder. It is recommended that the proper naming convention be followed. The point you need to remember is that the name of the Tag Helper should end with the suffix TagHelper. Our newly created MyCustomTagHelper class should be derived from the TagHelper class, which contains two virtual methods: Process and ProcessAsync. These methods are responsible for rendering the output of our custom Tag Helper, and we would use them according to our project’s requirements:

So, once you create the MyCustomTagHelper.cs class file, please copy and paste the following code.

using Microsoft.AspNetCore.Razor.TagHelpers;

namespace TagHelpersDemo.TagHelpers
{
    public class MyCustomTagHelper : TagHelper
    {
        public override void Process(TagHelperContext context, TagHelperOutput output)
        {

        }
    }
}

Parameters

TagHelperContext context: This parameter provides information about the environment in which the Tag Helper is executed. It contains details about the attributes applied to the Tag Helper element in the Razor view and other information about the surrounding context.

TagHelperOutput output: This parameter allows you to manipulate the HTML that will be output by the Tag Helper. It gives you control over what gets rendered to the view from your Tag Helper. TagHelperOutput has several important properties and methods:

  • TagName: Gets or sets the HTML element’s tag name. Changing this value can change the resulting tag or even remove it if set to null.
  • Attributes: A collection to manage the attributes of the tag. You can add, remove, or modify attributes.
  • Content: Manages the inner HTML of the element. You can set content, append content, or replace existing content.
Process Method Functionality

Within the Process method, we can use the output parameter to change the HTML output based on the logic we write. This could involve changing the tag itself, modifying attributes, or altering the inner content. The method does not return a value; instead, it directly modifies the output instance to produce the desired output.

Now, let us set some of the properties using TagHelperOutput. Modify the MyCustomTagHelper.cs class as follows. The following MyCustomTagHelper class is designed to output HTML content that displays details about an employee.

using Microsoft.AspNetCore.Razor.TagHelpers;
using System.Text;

namespace TagHelpersDemo.TagHelpers
{
    public class MyCustomTagHelper : TagHelper
    {
        // PascalCase gets translated into Camel-case.
        // Can be passed via <my-custom employee-id="..." />. 
        public int EmployeeId { get; set; }

        // Can be passed via <my-custom employee-name="..." />. 
        public string? EmployeeName { get; set; }

        // Can be passed via <my-custom designation="..." />. 
        public string? Designation { get; set; }

        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
            //TagName: The HTML element's tag name.
            //A whitespace or null value results in no start or end tag being rendered.
            output.TagName = "EmployeeSectionTagHelper"; // Set the HTML element name

            //TagMode: Syntax of the element in the generated HTML.
            //StartTagAndEndTag: Include both start and end tags.
            output.TagMode = TagMode.StartTagAndEndTag;

            //Create a String Builder Object to Hold the Employee Informations
            var sb = new StringBuilder();
            sb.AppendFormat($"<span>Employee Id:</span> <strong>{EmployeeId}</strong><br/>");
            sb.AppendFormat($"<span>Employee Name:</span> <strong>{EmployeeName}</strong><br/>");
            sb.AppendFormat($"<span>Employee Designation:</span> <strong>{Designation}</strong><br/>");

            //Convert the StringBuilder Object to String Type and
            //then set that string as the content either using SetContent and SetHtmlContent method
            //Content: Get or set the HTML element's main content.
            //SetHtmlContent: Sets the content.
            //output.Content.SetHtmlContent(sb.ToString());

            //output.Content.SetContent(sb.ToString());
            output.Content.SetHtmlContent(sb.ToString());
        }
    }
}
Understanding the Process Method

The Process method is where the actual logic for what the Tag Helper does is defined. This method manipulates the output based on the properties provided.

  • output.TagName: Sets the HTML tag to EmployeeSectionTagHelper. 
  • output.TagMode: Sets how the tag is rendered. TagMode.StartTagAndEndTag ensures that the output HTML will have both an opening and a closing tag, which is typical for content-containing elements.
  • StringBuilder: Used to construct the HTML content dynamically. It formats strings to include the employee’s ID, name, and designation in a structured format. Each employee attribute is wrapped within a <span> tag for the label and a <strong> tag for the value, providing a semantic and possibly stylable way to display the information.
  • output.Content.SetHtmlContent(sb.ToString()): This line adds the constructed HTML content to the output.Content. SetHtmlContent is used instead of SetContent to ensure that the HTML tags in the StringBuilder are rendered as HTML rather than plain text.
Adding addTagHelper to Views

In the next step, we need to add the addTagHelper directive to the Views/_ViewImports.cshtml file to make the Custom Tag Helper available to all the Razor views. We need to specify the Assembly Name (i.e., the Project name) where we created the Custom Tag Helper. This can be done as follows:
@addTagHelper *, TagHelpersDemo

Here, TagHelpersDemo is the assembly name where we have created our custom Tag Helper. So, with this Views/_ViewImports.cshtml file, it should look as follows.
@using TagHelpersDemo
@using TagHelpersDemo.Models
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, TagHelpersDemo

How Do We Use the Custom Tag Helper in ASP.NET Core MVC?

To use the custom Tag Helper in the Razor view, you need to write the Tag name in the lower case as shown in the below code snippet:

<my-custom employee-id=”1001″ employee-name=”Pranaya Rout” designation=”Manager”></my-custom>

As you can see, here we are using my-custom as an HTML Element and specifying the EmployeeId, EmployeeName, and Designation attributes of this my-custom tag. Next, modify the Home Controller as follows:

using Microsoft.AspNetCore.Mvc;
namespace TagHelpersDemo.Controllers
{
    public class HomeController : Controller
    {
        public IActionResult Index()
        {
            return View();
        }
    }
}

Next, modify the Index.cshtml view method as follows:

@{
    ViewBag.Title = "Index";
    Layout = null;
}

<my-custom employee-id="1001" employee-name="Pranaya Rout" designation="Manager"></my-custom>

With the above changes, run the application, and you will get the following output.

How to Create Custom Tag Helper in AS.NET Core MVC Application with Examples

If you inspect the generated HTML, you will see the following code generated.

<EmployeeSectionTagHelper>
    <span>Employee Id:</span> <strong>1001</strong><br/>
    <span>Employee Name:</span> <strong>Pranaya Rout</strong><br/>
    <span>Employee Designation:</span> <strong>Manager</strong><br/>
</EmployeeSectionTagHelper>
Passing Model Data to a Custom Tag Helper

We can also use the model binding techniques to pass the model data to a custom Tag Helper. In the following example, we will create three properties that take the given model expressions: EmployeeId, EmployeeName, and Designation. So, create a class file named Employee.cs within the Models folder and copy and paste the following code into it.

namespace TagHelpersDemo.Models
{
    public class Employee
    {
        public int EmployeeId { get; set; }
        public string? EmployeeName { get; set; }
        public string? Designation { get; set; }
    }
}

Next, modify the Index action method of the Home Controller as follows:

using Microsoft.AspNetCore.Mvc;
using TagHelpersDemo.Models;

namespace TagHelpersDemo.Controllers
{
    public class HomeController : Controller
    {
        public IActionResult Index()
        {
            Employee employee = new Employee()
            {
                EmployeeId = 1,
                EmployeeName = "Pranaya",
                Designation= "Manager"
            };
            return View(employee);
        }
    }
}

Next, modify the Index.cshtml view as follows:

@model Employee
@{
    ViewBag.Title = "Index";
    Layout = null;
}

<my-custom employee-id="@Model.EmployeeId" employee-name="@Model.EmployeeName" designation="@Model.Designation"></my-custom>

We don’t need to make any changes in our MyCustomTagHelper class. With these changes in place, run the application, and you will get the output as expected, as shown in the below image.

How to Create Custom Tag Helper in AS.NET Core MVC Application with Examples

Now, run the application, and you should get the output as expected.

Another Way to Pass Model Data to Custom Tag Helper:

First, modify the MyCustomTagHelper class as follows:

using Microsoft.AspNetCore.Razor.TagHelpers;
using System.Text;

namespace TagHelpersDemo.TagHelpers
{
    [HtmlTargetElement("employee-details")]
    public class MyCustomTagHelper : TagHelper
    {
        [HtmlAttributeName("for-id")]
        public int EmployeeId { get; set; }

        [HtmlAttributeName("for-name")]
        public string? EmployeeName { get; set; }

        [HtmlAttributeName("for-designation")]
        public string? Designation { get; set; }

        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
            //TagName: The HTML element's tag name.
            //A whitespace or null value results in no start or end tag being rendered.
            output.TagName = "EmployeeSectionTagHelper"; // Set the HTML element name

            //TagMode: Syntax of the element in the generated HTML.
            //StartTagAndEndTag: Include both start and end tags.
            output.TagMode = TagMode.StartTagAndEndTag;

            //Create a String Builder Object to Hold the Employee Informations
            var sb = new StringBuilder();
            sb.AppendFormat($"<span>Employee Id:</span> <strong>{EmployeeId}</strong><br/>");
            sb.AppendFormat($"<span>Employee Name:</span> <strong>{EmployeeName}</strong><br/>");
            sb.AppendFormat($"<span>Employee Designation:</span> <strong>{Designation}</strong><br/>");

            //Convert the StringBuilder Object to String Type and
            //then set that string as the content either using SetContent and SetHtmlContent method
            //Content: Get or set the HTML element's main content.
            //SetHtmlContent: Sets the content.
            //output.Content.SetHtmlContent(sb.ToString());

            //output.Content.SetContent(sb.ToString());
            output.Content.SetHtmlContent(sb.ToString());
        }
    }
}

Next, modify the Index.cshtml view as follows:

@model Employee
@{
    ViewBag.Title = "Index";
    Layout = null;
}


<employee-details for-id="@Model.EmployeeId" for-name="EmployeeName" for-designation="Designation"></employee-details>

<br/><br/>

<employee-details for-id="@Model.EmployeeId" for-name="@Model.EmployeeName" for-designation="@Model.Designation"></employee-details>
Custom Tag Helpers Real-Time Examples in ASP.NET Core MVC

As we already discussed, Custom Tag Helpers in ASP.NET Core MVC is a powerful way to enhance the HTML rendering process by adding custom behavior or transformations to specific tags or attributes. They enable server-side code to generate or manipulate HTML elements in Razor views. Let’s look at a couple of real-time examples of Custom Tag Helpers in ASP.NET Core MVC Applications:

Email Obfuscate Tag Helper

Imagine you want to protect email addresses on your site from being used by spambots. Obfuscate meaning is to make something less clear and harder to understand, especially intentionally. One approach is to obfuscate the email address in the HTML. We can create a Custom Tag Helper and Obfuscate the email address for this. So, create a class file named EmailTagHelper.cs and copy and paste the following code into it.

using Microsoft.AspNetCore.Razor.TagHelpers;
using System.Net;

namespace TagHelpersDemo.Models
{
    //We need to access this Custom tag using using the tag called email
    [HtmlTargetElement("email")]
    public class EmailTagHelper : TagHelper
    {
        private const string EmailDomain = "dotnettutorials.net";

        // Can be passed via <email mail-to="..." />. 
        // PascalCase gets translated into kebab-case.
        public string MailTo { get; set; }

        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
            // Change the tag name to <a>
            // Replaces <email> with <a> tag
            output.TagName = "a";    

            var address = MailTo + "@" + EmailDomain;

            //Set the href attribute of the anchot tag as the email address
            output.Attributes.SetAttribute("href", "mailto:" + address);
            var obfuscatedEmail = "Email Us";
           
            output.Content.SetContent(obfuscatedEmail);
        }
    }
}

Next, modify the Index.cshtml view as follows:

@{
    ViewBag.Title = "Index";
    Layout = null;
}

<email mail-to="info"></email>

Now, run the application and see the following in the browser.

Custom Tag Helpers Real-Time Examples in ASP.NET Core MVC

If you inspect the generated HTML, you will see that the following HTML code is generated behind the scenes.

<a href="mailto:info@dotnettutorials.net">Email Us</a>
External Link Tag Helper

If you want to ensure that external links open in a new tab and are marked with a specific CSS class, you can use Custom Tag Helper. So, create a class file named ExternalLinkTagHelper.cs and then copy and paste the following code into it.

using Microsoft.AspNetCore.Razor.TagHelpers;

namespace TagHelpersDemo.Models
{
    [HtmlTargetElement("a", Attributes = "external-link")]
    public class ExternalLinkTagHelper : TagHelper
    {
        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
            output.Attributes.SetAttribute("target", "_blank");
            //output.Attributes.SetAttribute("rel", "noopener noreferrer");
            output.Attributes.Add("class", "external-link");
        }
    }
}

Next, modify the Index.cshtml file as follows.

@{
    ViewBag.Title = "Index";
    Layout = null;
}

<a href="https://dotnettutorials.net" external-link> Visit Dot Net Tutorials</a>

In the next article, I will discuss View Component Tag Helper in ASP.NET Core MVC Applications. In this article, I explain how to create a custom tag helper in an ASP.NET Core MVC application with examples. I hope you enjoy this article on creating a custom tag helper in the ASP.NET Core MVC.

Leave a Reply

Your email address will not be published. Required fields are marked *