Practical .NET

The Fundamentals of Improving Productivity with Custom Tag Helpers in ASP.NET Core

Some time back I wrote a post on a custom HtmlHelper that generated my typical block of HTML: A fieldset element containing a label, a textbox and a validation message element. Since then, in ASP.NET Core, tag helpers have come along as a replacement for (or complement to) HtmlHelpers.

HtmlHelpers vs. Tag Helpers
Unlike HtmlHelpers, a tag helper is a class that attaches itself to an HTML-compliant element in a View or Razor Page. The tag helper can, through its properties, add additional attributes to the element that a developer can use to customize the tag's behavior. At compile time, the code in the tag helper's Process (or ProcessAsync) method manipulates the element the tag helper is attached to in order to create the HTML that appears in the Web page that goes to the user.

While the way you invoke tag helpers is different than HtmlHelper, fundamentally, the goal is the same: Provide a convenient way to generate HTML in a View (or Razor Page) for those developers who don't want to have to write all the HTML themselves. If you have some HTML that you can see yourself repeating in multiple pages and (a) want to make yourself more efficient or (b) want to ensure consistency in your UI across those pages, tag helpers (like HtmlHelpers) can make a lot of sense.

Tag helpers also centralize the generation of that HTML. If you should decide to change/update the HTML being generated, you don't have to touch each page -- you just rewrite your tag helper and roll it out to the Web sites that use it. And, because tag helpers are just a class, that's easy to do: You can create your tag help in a Class Library project and share the resulting class across multiple projects/sites.

During processing your code can modify both the element it's attached to and any content inside the element's open and close tags. You can add or remove attributes and even change the tag's name. You can also add HTML immediately before or after the element that your helper is attached to.

Tag helpers are especially good news for page designers. Because tag helpers attach themselves to HTML elements, page designers get to work with tags they actually understand (unlike HtmlHelpers that are, essentially, opaque to anyone with HTML and CSS knowledge). That IntelliSense support for tag helpers is better than what you get with HtmlHelpers is just icing on the cake.

Attaching to a Tag
There are two ways to attach a tag helper class to an HTML-compliant element. The most straightforward way is to give the class the same name as the tag. A tag helper must inherit from the TagHelper class, so a tag helper that attaches itself to the Label tag would look like this:

public class Label: TagHelper 
{

However, you don't need to create tag helpers that attach just to existing HTML elements -- your helper will attach itself to any HTML-compliant element. For example, every one of your sites probably has a contact e-mail address on it. Odds are that the contact person varies from site to site but that the domain name (your organization) remains the same. As a result, it would be convenient to have a tag helper that would attach itself to a tag that looks like this:

<contact domain-name="phvis.com">phvogel</contact>

And then, at compile time, deliver this anchor tag to the browser:

<a href="mailto:[email protected]">Contact</a>

You can do that simply by creating a tag helper called Contact.

There are other benefits to creating tag helpers. If, for example, you change your mind and decide you want your mailto Contact element to be replaced with an anchor tag that takes the user to a page filled with contact options (e-mail, online chat, phone numers and so on) ... well, all you have to do is rewrite your tag helper to generate the new tag.

Enhancing Multiple Tags
But there's more flexibility here than just attaching your helper to specific tags. There's nothing stopping you from creating a tag helper that attaches itself to any element that meets criteria that you set. You do that by decorating your tag helper class with the HtmlTargetElement attribute. That attribute lets you specify some combination of element name, attributes and attribute values that will be used when attaching your tag helper to an element.

This code, for example, attaches itself to any element with a tag name of input and an attribute called type that's set to "email":

[HtmlTargetElement("input", attributes="[type=email]")]
public class Contact : TagHelper

Now, you can piggyback your tag helper with its domain-name attribute onto an HTML element that looks like this:

<input type="email" domain-name="phvis.com" value="peter.vogel "/>

The output would be the same: an anchor tag that replaces this input tag. I don't even have to specify a tag name -- using the HtmlTargetElement, my tag helper can extend any HTML-compliant element I want based solely on what attributes that element has.

Unfortunately, as fond as I am of tag helpers, I have to regard them as a complement to HtmlHelpers rather than a replacement. There's at least one limitation to tag helpers that makes recreating my HtmlHelper as a tag helper impossible and I'm not willing to give that HtmlHelper up. To explain why that is, I'll have to drag you through the ugly details of creating a tag helper, starting in my next column.

About the Author

Peter Vogel is a system architect and principal in PH&V Information Services. PH&V provides full-stack consulting from UX design through object modeling to database design. Peter tweets about his VSM columns with the hashtag #vogelarticles. His blog posts on user experience design can be found at http://blog.learningtree.com/tag/ui/.

comments powered by Disqus

Featured

  • Hands On: New VS Code Insiders Build Creates Web Page from Image in Seconds

    New Vision support with GitHub Copilot in the latest Visual Studio Code Insiders build takes a user-supplied mockup image and creates a web page from it in seconds, handling all the HTML and CSS.

  • Naive Bayes Regression Using C#

    Dr. James McCaffrey from Microsoft Research presents a complete end-to-end demonstration of the naive Bayes regression technique, where the goal is to predict a single numeric value. Compared to other machine learning regression techniques, naive Bayes regression is usually less accurate, but is simple, easy to implement and customize, works on both large and small datasets, is highly interpretable, and doesn't require tuning any hyperparameters.

  • VS Code Copilot Previews New GPT-4o AI Code Completion Model

    The 4o upgrade includes additional training on more than 275,000 high-quality public repositories in over 30 popular programming languages, said Microsoft-owned GitHub, which created the original "AI pair programmer" years ago.

  • Microsoft's Rust Embrace Continues with Azure SDK Beta

    "Rust's strong type system and ownership model help prevent common programming errors such as null pointer dereferencing and buffer overflows, leading to more secure and stable code."

  • Xcode IDE from Microsoft Archrival Apple Gets Copilot AI

    Just after expanding the reach of its Copilot AI coding assistant to the open-source Eclipse IDE, Microsoft showcased how it's going even further, providing details about a preview version for the Xcode IDE from archrival Apple.

Subscribe on YouTube

Upcoming Training Events