Marking HTML-elements active based on the current route using ASP.NET MVC Tag Helpers

Adding class="active" is a fairly common practice for highlighting HTML-elements, especially when using the Twitter Bootstrap framework. Usually you want to let a specific list item stand out of your main navigation, indicating the section the user is currently visiting. Take for example the upper right part of this website:

In this post I'll explain how I implemented this behavior dynamically with ASP.NET Core MVC using Tag-Helpers.

Introducing MVC Tag-Helpers

Somehow my View written in Razor must be able to add an HTML class attribute dynamically based on given MVC routing parameters. This is where MVC Tag-Helpers come into play:

Tag Helpers enable server-side code to participate in creating and rendering HTML elements in Razor files.

Okay, cool, a bit like the old HTML helpers, but attached to HTML elements in the Razor view rather than invoked as a method. Looking at the source code in GitHub of the Microsoft.AspNetCore.Mvc.TagHelpers namespace, we can see a whole bunch of TagHelpers. It's interesting to see how for instance the LabelTagHelper works when compared to a view using it:

NavLinkTagHelper from TagHelperSamples

By coincidence I stumbled upon this TagHelperSamples project, which contains a NavLinkTagHelper that actually comes pretty close to the implementation we need. It extends the AnchorTagHelper and allows you to match the Controller and optionally an Action.

The following code snippets show how you can leverage this helper.

A better NavLinkTagHelper

The NavLinkTagHelper from the TagHelperSamples project matches 80% of my needs. Mostly I just want to match the controller, and optionally an action. What if you need to match more parameters? For example, my categories sidebar provide an additional category name, and I want to highlight the selected category (if any).

I've forked my own copy of the original repository and made some minor adjustments. I've also created a pull request, so the original authors might pull in the changes. Until then you might be better off just copying the helper itself: