How to add “active” class to Html.ActionLink in ASP.NET MVC

I’m trying to add an”active” class to my bootstrap navbar in MVC, but the following doesn’t show the active class when written like this:

<ul class="nav navbar-nav">
  <li>@Html.ActionLink("Home", "Index", "Home", null, new {@class="active"})</li>
  <li>@Html.ActionLink("About", "About", "Home")</li>
  <li>@Html.ActionLink("Contact", "Contact", "Home")</li>
</ul>

This resolves to what looks like a correctly formatted class, but doesn’t work:

<a class="active" href="/" rel="nofollow noreferrer noopener">Home</a>

In the Bootstrap documentation it states that ‘a’ tags shouldn’t be used in the navbar, but the above is how I believe is the correct way of adding a class to an Html.ActionLink. Is there another (tidy) way I can do this?

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

In Bootstrap the active class needs to be applied to the <li> element and not the <a>. See the first example here: http://getbootstrap.com/components/#navbar

The way you handle your UI style based on what is active or not has nothing to do with ASP.NET MVC’s ActionLink helper. This is the proper solution to follow how the Bootstrap framework was built.

<ul class="nav navbar-nav">
    <li class="active">@Html.ActionLink("Home", "Index", "Home")</li>
    <li>@Html.ActionLink("About", "About", "Home")</li>
    <li>@Html.ActionLink("Contact", "Contact", "Home")</li>
</ul>

Edit:

Since you will most likely be reusing your menu on multiple pages, it would be smart to have a way to apply that selected class automatically based on the current page rather than copy the menu multiple times and do it manually.

The easiest way is to simply use the values contained in ViewContext.RouteData, namely the Action and Controller values. We could build on what you currently have with something like this:

<ul class="nav navbar-nav">
    <li class="@(ViewContext.RouteData.Values["Action"].ToString() == "Index" ? "active" : "")">@Html.ActionLink("Home", "Index", "Home")</li>
    <li class="@(ViewContext.RouteData.Values["Action"].ToString() == "About" ? "active" : "")">@Html.ActionLink("About", "About", "Home")</li>
    <li class="@(ViewContext.RouteData.Values["Action"].ToString() == "Contact" ? "active" : "")">@Html.ActionLink("Contact", "Contact", "Home")</li>
</ul>

It’s not pretty in code, but it’ll get the job done and allow you to extract your menu into a partial view if you like. There are ways to do this in a much cleaner way, but since you’re just getting started I’ll leave it at that. Best of luck learning ASP.NET MVC!


Late edit:

This question seems to be getting a bit of traffic so I figured I’d throw in a more elegant solution using an HtmlHelper extension.

Edit 03-24-2015: Had to rewrite this method to allow for multiple actions and controllers triggering the selected behavior, as well as handling for when the method is called from a child action partial view, thought I’d share the update!

public static string IsSelected(this HtmlHelper html, string controllers = "", string actions = "", string cssClass = "selected")
{
    ViewContext viewContext = html.ViewContext;
    bool isChildAction = viewContext.Controller.ControllerContext.IsChildAction;

    if (isChildAction)
        viewContext = html.ViewContext.ParentActionViewContext;

    RouteValueDictionary routeValues = viewContext.RouteData.Values;
    string currentAction = routeValues["action"].ToString();
    string currentController = routeValues["controller"].ToString();

    if (String.IsNullOrEmpty(actions))
        actions = currentAction;

    if (String.IsNullOrEmpty(controllers))
        controllers = currentController;

    string[] acceptedActions = actions.Trim().Split(',').Distinct().ToArray();
    string[] acceptedControllers = controllers.Trim().Split(',').Distinct().ToArray();

    return acceptedActions.Contains(currentAction) && acceptedControllers.Contains(currentController) ?
        cssClass : String.Empty;
}

Works with .NET Core:

public static string IsSelected(this IHtmlHelper htmlHelper, string controllers, string actions, string cssClass = "selected")
{
    string currentAction = htmlHelper.ViewContext.RouteData.Values["action"] as string;
    string currentController = htmlHelper.ViewContext.RouteData.Values["controller"] as string;

    IEnumerable<string> acceptedActions = (actions ?? currentAction).Split(',');
    IEnumerable<string> acceptedControllers = (controllers ?? currentController).Split(',');

    return acceptedActions.Contains(currentAction) && acceptedControllers.Contains(currentController) ?
        cssClass : String.Empty;
}

Sample usage:

<ul>
    <li class="@Html.IsSelected(actions: "Home", controllers: "Default")">
        <a href="@Url.Action(" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener"Home", "Default")">Home</a>
    </li>
    <li class="@Html.IsSelected(actions: "List,Detail", controllers: "Default")">
        <a href="@Url.Action(" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener"List", "Default")">List</a>
    </li>
</ul>

Method 2

Extension:

public static MvcHtmlString LiActionLink(this HtmlHelper html, string text, string action, string controller)
{
    var context = html.ViewContext;
    if (context.Controller.ControllerContext.IsChildAction)
        context = html.ViewContext.ParentActionViewContext;
    var routeValues = context.RouteData.Values;
    var currentAction = routeValues["action"].ToString();
    var currentController = routeValues["controller"].ToString();

    var str = String.Format("<li role="presentation"{0}>{1}</li>",
        currentAction.Equals(action, StringComparison.InvariantCulture) &&
        currentController.Equals(controller, StringComparison.InvariantCulture) ?
        " class="active"" :
        String.Empty, html.ActionLink(text, action, controller).ToHtmlString()
    );
    return new MvcHtmlString(str);
}

Usage:

<ul class="nav navbar-nav">
    @Html.LiActionLink("About", "About", "Home")
    @Html.LiActionLink("Contact", "Contact", "Home")
</ul>

Method 3

I manged to do this by adding a view bag parameter in asp.net mvc. Here what have i done

Added ViewBag.Current = "Scheduler"; like parameter in each page

In layout page

<ul class="nav navbar-nav">
     <li class="@(ViewBag.Current == "Scheduler" ? "active" : "") "><a href="@Url.Action(" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener"Index","Scheduler")" target="_self">Scheduler</a></li>
 </ul>

This solved my problem.

Method 4

May be little late. But hope this helps.

public static class Utilities
{
    public static string IsActive(this HtmlHelper html, 
                                  string control,
                                  string action)
    {
        var routeData = html.ViewContext.RouteData;

        var routeAction = (string)routeData.Values["action"];
        var routeControl = (string)routeData.Values["controller"];

        // both must match
        var returnActive = control == routeControl &&
                           action == routeAction;

        return returnActive ? "active" : "";
    }
}

And usage as follow:

<div class="navbar-collapse collapse">
    <ul class="nav navbar-nav">
        <li class='@Html.IsActive("Home", "Index")'>
            @Html.ActionLink("Home", "Index", "Home")
        </li>
        <li class='@Html.IsActive("Home", "About")'>
            @Html.ActionLink("About", "About", "Home")
        </li>
        <li class='@Html.IsActive("Home", "Contact")'>
            @Html.ActionLink("Contact", "Contact", "Home")
        </li>
    </ul>
</div>

Got reference from http://www.codingeverything.com/2014/05/mvcbootstrapactivenavbar.html

Method 5

Easy ASP.NET Core 3.0 and TagHelpers

[HtmlTargetElement("li", Attributes = "active-when")]
public class LiTagHelper : TagHelper
{
    public string ActiveWhen { get; set; }

    [ViewContext]
    [HtmlAttributeNotBound]
    public ViewContext ViewContextData { get; set; }

    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        if (ActiveWhen == null)
            return;

        var targetController = ActiveWhen.Split("/")[1];
        var targetAction = ActiveWhen.Split("/")[2];

        var currentController = ViewContextData.RouteData.Values["controller"].ToString();
        var currentAction = ViewContextData.RouteData.Values["action"].ToString();

        if (currentController.Equals(targetController) && currentAction.Equals(targetAction))
        {
            if (output.Attributes.ContainsName("class"))
            {
                output.Attributes.SetAttribute("class", $"{output.Attributes["class"].Value} active");
            }
            else
            {
                output.Attributes.SetAttribute("class", "active");
            }
        }
    }
}

Include into your _ViewImports.cs:

@addTagHelper *, YourAssemblyName

Usage:

 <li active-when="/Home/Index">

Method 6

ASP.NET Core & Bootstrap 4

Most up-to-date answer

I have re-worked @crush‘s neat solution for an updated, ASP.NET Core and Bootstrap 4 compatible way to solve this problem based on an IHtmlHelper extension method:

public static class LinkExtensions
{
    public static IHtmlContent ActiveActionLink(this IHtmlHelper html, string linkText, string actionName, string controllerName, object routeValues, object htmlAttributes)
    {
        return ActiveActionLink(html, linkText, actionName, controllerName, new RouteValueDictionary(routeValues), HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
    }

    public static IHtmlContent ActiveActionLink(this IHtmlHelper html, string linkText, string actionName, string controllerName, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes)
    {
        var routeData = html.ViewContext.RouteData;
        var routeAction = (string)routeData.Values["action"];
        var routeController = (string)routeData.Values["controller"];

        var active = controllerName.Equals(routeController) && actionName.Equals(routeAction);

        using (var writer = new StringWriter())
        {
            writer.WriteLine($"<li class='nav-item {(active ? "active" : "")}'>");
            html.ActionLink(linkText, actionName, controllerName, routeValues, htmlAttributes).WriteTo(writer, HtmlEncoder.Default);
            writer.WriteLine("</li>");
            return new HtmlString(writer.ToString());
        }
    }
}

Usage

<nav class="navbar">
    <div class="collapse navbar-collapse">
        <ul class="navbar-nav">
            @Html.ActiveActionLink("Home", "Index", "Home", null, new { @class = "nav-link" })
            @Html.ActiveActionLink("About", "About", "Home", null, new { @class = "nav-link" })
            @Html.ActiveActionLink("Contact", "Contact", "TimeTracking", null, new { @class = "nav-link" })
        </ul>
    </div>
</nav>

Method 7

I know this question is old, but I will just like to add my voice here. I believe it is a good idea to leave the knowledge of whether or not a link is active to the controller of the view.

I would just set a unique value for each view in the controller action. For instance, if I wanted to make the home page link active, I would do something like this:

public ActionResult Index()
{            
    ViewBag.Title = "Home";
    ViewBag.Home = "class = active";
    return View();
}

Then in my view, I will write something like this:

<li @ViewBag.Home>@Html.ActionLink("Home", "Index", "Home", null, new { title = "Go home" })</li>

When you navigate to a different page, say Programs, ViewBag.Home does not exist (instead ViewBag.Programs does); therefore, nothing is rendered, not even class=””. I think this is cleaner both for maintainability and cleanliness. I tend to always want to leave logic out of the view as much as I can.

Method 8

Considering what Damith posted, I like to think you can just qualify active by the Viewbag.Title (best practice is to populate this in your content pages allowing your _Layout.cshtml page to hold your link bars). Also note that if you are using sub-menu items it also works fine:

<li class="has-sub @(ViewBag.Title == "Dashboard 1" || ViewBag.Title == "Dashboard 2" ? "active" : "" )">
    <a href="javascript:;" rel="nofollow noreferrer noopener">
        <b class="caret"></b>
        <i class="fa fa-th-large"></i>
        <span>Dashboard</span>
    </a>
    <ul class="sub-menu">
        <li class="@(ViewBag.Title == "Dashboard 1" ? "active" : "")"><a href="index.html" rel="nofollow noreferrer noopener">Dashboard v1</a></li>
        <li class="@(ViewBag.Title == "Dashboard 2" ? "active" : "")"><a href="index_v2.html" rel="nofollow noreferrer noopener">Dashboard v2</a></li>
    </ul>
</li>

Method 9

This solution is simple for Asp.net MCV 5.

  1. Create a static class, for example Utilitarios.cs.
  2. Inside the Class create a static method:
    public static string IsLinkActive(this UrlHelper url, string action, string controller)
    {
        if (url.RequestContext.RouteData.Values["controller"].ToString() == controller &&
            url.RequestContext.RouteData.Values["action"].ToString() == action)
        {
            return "active";
        }
    
        return "";
    }
  3. call like this
    <ul class="sidebar-menu" data-widget="tree">
        <li class="header">HEADER</li>
        <li class="@Url.IsLinkActive("Index", "Home")">
            <a href="@Url.Action(" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener"Index", "Home")"><i class="fa fa-link"></i> <span>Home</span></a>
        </li>
        <li class="@Url.IsLinkActive("About", "Home")">
            <a href="@Url.Action(" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener"About", "Home")"><i class="fa fa-link"></i><span>About</span></a>
        </li>
    </ul>
    

Method 10

I created an HtmlHelper extension that adds an ActiveActionLink method for those of you who want to add the “active” class to the link itself rather than the <li> surrounding the link.

public static class LinkExtensions
{
    public static MvcHtmlString ActiveActionLink(this HtmlHelper html, string linkText, string actionName, string controllerName, object routeValues, object htmlAttributes)
    {
        return ActiveActionLink(html, linkText, actionName, controllerName, new RouteValueDictionary(routeValues), HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
    }

    public static MvcHtmlString ActiveActionLink(this HtmlHelper html, string linkText, string actionName, string controllerName, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes)
    {
        const string activeClassName = "active";

        var routeData = html.ViewContext.RouteData;

        var routeAction = (string)routeData.Values["action"];
        var routeController = (string)routeData.Values["controller"];

        var active = controllerName.Equals(routeController) && actionName.Equals(routeAction);

        if (active)
        {
            var @class = (string)htmlAttributes["class"];

            htmlAttributes["class"] = string.IsNullOrEmpty(@class)
                ? activeClassName
                : @class + " active";
        }

        var link = html.ActionLink(linkText, actionName, controllerName, routeValues, htmlAttributes);

        return link;
    }
}

Usage is as follows:

@Html.ActiveActionLink("Home", "Index", "Home", new { area = "" }, new { @class = "nav-item nav-link" })

Method 11

I modified dom’s “not pretty” answer and made it uglier. Sometimes two controllers have the conflicting action names (i.e. Index) so I do this:

<ul class="nav navbar-nav">
  <li class="@(ViewContext.RouteData.Values["Controller"].ToString() + ViewContext.RouteData.Values["Action"].ToString() == "HomeIndex" ? "active" : "")">@Html.ActionLink("Home", "Index", "Home")</li>
  <li class="@(ViewContext.RouteData.Values["Controller"].ToString() + ViewContext.RouteData.Values["Action"].ToString() == "AboutIndex" ? "active" : "")">@Html.ActionLink("About", "Index", "About")</li>
  <li class="@(ViewContext.RouteData.Values["Controller"].ToString() + ViewContext.RouteData.Values["Action"].ToString() == "ContactHome" ? "active" : "")">@Html.ActionLink("Contact", "Contact", "Home")</li>
</ul>

Method 12

You can try this:
In my case i am loading menu from database based on role based access, Write the code on your every view which menu your want to active based on your view.

<script type="text/javascript">
        $(document).ready(function () {         
            $('li.active active-menu').removeClass('active active-menu');
            $('a[href="/MgtCustomer/Index" rel="nofollow noreferrer noopener"]').closest('li').addClass('active active-menu');
        });
</script>

Method 13

is possible with a lambda function

@{
string controllerAction = ViewContext.RouteData.Values["Controller"].ToString() + ViewContext.RouteData.Values["Action"].ToString();
    Func<string, string> IsSelected= x => x==controllerAction ? "active" : "";
}

then usage

 @Html.ActionLink("Inicio", "Index", "Home", new { area = "" }, new { @class = IsSelected("HomeIndex")})

Method 14

Most of the solutions on this question all require you to specify the ‘page’ on both the li and the a (via HtmlHelper) tag. Both @Wolles and @Crush‘s answers eliminated this duplication, which was nice, but they were using HtmlHelper extension methods instead of TagHelpers. And I wanted to use a TagHelper and support Razor Pages.

You can read my full post here (and get the source code), but the gist of it is:

<bs-menu-link asp-page="/Events/Index" menu-text="Events"></bs-menu-link>

Would render (if the link was active obviously):

<li class="active"><a href="/Events">Events</a></li>

My TagHelper leverages the AnchorTagHelper internally (thus supporting asp-page, asp-controller, asp-action, etc. attributes). The ‘checks’ for active or not is similar to many of the answers to this post.

Method 15

Add ‘.ToString’ to improve comparing on ASP.NET MVC

<ul class="nav navbar-nav">
<li class="@(ViewContext.RouteData.Values["Action"].ToString() == "Index" ? "active" : "")">@Html.ActionLink("Home", "Index", "Home")</li>
<li class="@(ViewContext.RouteData.Values["Action"].ToString() == "About" ? "active" : "")">@Html.ActionLink("About", "About", "Home")</li>
<li class="@(ViewContext.RouteData.Values["Action"].ToString() == "Contact" ? "active" : "")">@Html.ActionLink("Contact", "Contact", "Home")</li>

Method 16

We also can create UrlHelper from RequestContext which we can get from MvcHandler itself. Therefore I beleive for someone who wants to keep this logic in Razor templates following way would be helpful:

  1. In project root create a folder named AppCode.
  2. Create a file there named HtmlHelpers.cshtml
  3. Create a helper in there:
    @helper MenuItem(string action, string controller)
    {
         var mvcHandler = Context.CurrentHandler as MvcHandler;
         if (mvcHandler != null)
         {
             var url = new UrlHelper(mvcHandler.RequestContext);
             var routeData = mvcHandler.RequestContext.RouteData;
             var currentAction = routeData.Values["action"].ToString();
             var currentController = routeData.Values["controller"].ToString();
             var isCurrent = string.Equals(currentAction, action, StringComparison.InvariantCultureIgnoreCase) &&
                             string.Equals(currentController, controller, StringComparison.InvariantCultureIgnoreCase);
    
            <div class="@(isCurrent ? "active" : "")">
                <div>@url.Action(action, controller)</div>
            </div>
         }   
    }
  4. Then we can use on our views like this:
    @HtmlHelpers.MenuItem("Default", "Home")

Hope that it helps to someone.

Method 17

I would like to propose this solution which is based on the first part of Dom’s answer.

We first define two variables, “action” and “controller” and use them to determine the active link:

{ string controller = ViewContext.RouteData.Values["Controller"].ToString();
string action = ViewContext.RouteData.Values["Action"].ToString();}

And then:

<ul class="nav navbar-nav">
    <li class="@((controller == "Home" && action == "Index") ? "active" : "")">@Html.ActionLink("Home", "Index", "Home")</li>
    <li class="@((controller == "Home" && action == "About") ? "active" : "")">@Html.ActionLink("About", "About", "Home")</li>
    <li class="@((controller == "Home" && action == "Contact") ? "active" : "")">@Html.ActionLink("Contact", "Contact", "Home")</li>
</ul>

Now it looks nicer and no need for more complex solutions.

Method 18

the answer by @dombenoit works. Though it introduces some code to maintain. Check this syntax out:

using (var nav = Html.Bootstrap().Begin(new Nav().Style(NavType.NavBar).SetLinksActiveByControllerAndAction()))
{
    @nav.ActionLink("Link 1", "action1")
    @nav.ActionLink("Link 2", "action2")
    @nav.Link("External Link", "#")
}

Notice the use of .SetLinksActiveByControllerAndAction() method.

If you wonder what makes this syntax possible, check out TwitterBootstrapMVC

Method 19

I also was looking for a solution and jQuery helped pretty much. First, you need to give ‘id’s to your <li> elements.

<li id="listguides"><a href='/Guides/List'>List Guides</a></li>

After doing this in your layout page, you can tell jQuery which <li> element should be ‘selected’ in your view.

@section Scripts{
    <script type="text/javascript">
        $('#listguides').addClass('selected');
    </script>
}

Note: You need to have @RenderSection("scripts", required: false) in your layout page, just before the </body> tag to add that section.

Method 20

I realized that this problem was a common problem for some of us, so I published my own solution using nuget package. Below you can see how it works. I hope that will be useful.

Note:This nuget package is my first package. So if you see a mistake, please give feedback. Thank you.

  1. Install Package or download source code and add your Project
    -Install-Package Betalgo.MvcMenuNavigator
  2. Add your pages to an enum
    public enum HeaderTop
    {
        Dashboard,
        Product
    }
    public enum HeaderSub
    {
        Index
    }
  3. Put Filter to top of your Controllor or Action
    [MenuNavigator(HeaderTop.Product, HeaderSub.Index)]
    public class ProductsController : Controller
    {
        public async Task<ActionResult> Index()
        {
            return View();
        }
    
        [MenuNavigator(HeaderTop.Dashboard, HeaderSub.Index)]
        public async Task<ActionResult> Dashboard()
        {
            return View();
        }
    }
  4. And use it In your header layout like this
    @{
    var headerTop = (HeaderTop?)MenuNavigatorPageDataNavigatorPageData.HeaderTop;
    var headerSub = (HeaderSub?)MenuNavigatorPageDataNavigatorPageData.HeaderSub;
    }
    <div class="nav-collapse collapse navbar-collapse navbar-responsive-collapse">
    <ul class="nav navbar-nav">
        <li class="@(headerTop==HeaderTop.Dashboard?"active selected open":"")">
            <a href="@Url.Action(" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener"Index","Home")">Dashboard</a>
        </li>
        <li class="@(headerTop==HeaderTop.Product?"active selected open":"")">
            <a href="@Url.Action(" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener"Index", "Products")">Products</a>
        </li>
    </ul>

More Info: https://github.com/betalgo/MvcMenuNavigator

Method 21

I believe here is a cleaner and smalller code to do get the selected menu being “active”:

 <ul class="navbar-nav mr-auto">
                <li class="nav-item @Html.IfSelected("Index")">
                    <a class="nav-link" href="@Url.Action(" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener"Index", "Home")">Home</a>
                </li>
                <li class="nav-item @Html.IfSelected("Controls")">
                    <a class="nav-link" href="@Url.Action(" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener"Controls", "Home")">MVC Controls</a>
                </li>
                <li class="nav-item @Html.IfSelected("About")">
                    <a class="nav-link" href="@Url.Action(" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener"About", "Home")">About</a>
                </li>
</ul>

 public static string IfSelected(this HtmlHelper html, string action)
        {
            return html
                       .ViewContext
                       .RouteData
                       .Values["action"]
                       .ToString() == action
                            ? " active"
                            : "";
        }

Method 22

I found a solution for multiple routes.
TagHelper:

[HtmlTargetElement("li", Attributes = "active-when")]
    public class ActiveTagHelper : TagHelper
    {
        [HtmlAttributeName("active-when")]
        public string ActiveWhen { get; set; }

        [ViewContext]
        [HtmlAttributeNotBound]
        public ViewContext ViewContext { get; set; }

        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
            if (ActiveWhen == null)
                return;

            var hrefs = ActiveWhen.Split(",");

            var currentController = ViewContext.RouteData.Values["controller"].ToString();
            var currentAction = ViewContext.RouteData.Values["action"].ToString();

            foreach (var item in hrefs)
            {
                var targetController = item.Split("/")[1];
                var targetAction = item.Split("/")[2];

                if (currentController.Equals(targetController) && currentAction.Equals(targetAction))
                {
                    if (output.Attributes.ContainsName("class"))
                    {
                        output.Attributes.SetAttribute("class", $"{output.Attributes["class"].Value} active");
                    }
                    else
                    {
                        output.Attributes.SetAttribute("class", "active");
                    }
                }
            }
        }
    }

Import:

@addTagHelper *, YourProjectName

Usage:

   <li class="nav-item" active-when="/Product/Index,/Product/Add"></li>

Method 23

At top of the layout page,

@{ var _path = Context.Request.Path.ToString();}

and in your navbar,

<a class="nav-link dropdown-toggle @(_path.Contains("UTBulkFlights") ? "active" : "")">abcLink</a>

Method 24

if is it is not showing at all, the reason is that you need two @ sign:

@@class

BUT, I believe you might need to have the active class on the “li” tag not on the “a” tag. according too bootstrap docs (http://getbootstrap.com/components/#navbar-default):

<ul class="nav navbar-nav">
  <li class="active"><a href="#" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener">Home</a></li>
  <li><a href="#" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener">Profile</a></li>
  <li><a href="#" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener" rel="nofollow noreferrer noopener">Messages</a></li>
</ul>

therefore your code will be:

<ul class="nav navbar-nav">
  <li class="active">@Html.ActionLink("Home", "Index", "Home", null)</li>
  <li>@Html.ActionLink("About", "About", "Home")</li>
  <li>@Html.ActionLink("Contact", "Contact", "Home")</li>
</ul>

Method 25

I have make combination of answers above and made my solution.

So..

First in razor block create one string variable which will contain name value of controller and action that is called by user.

    @{
        string controllerAction =  ViewContext.RouteData.Values["Controller"].ToString() + ViewContext.RouteData.Values["Action"].ToString(); 
    }

Then use combination of HTML and Razor code:

    <ul class="nav navbar-nav">
        <li class="@(controllerAction == "HomeIndex" ? "active" : "" )">@Html.ActionLink("Home", "Index", "Home")</li>
        <li class="@(controllerAction == "AboutIndex" ? "active" : "" )">@Html.ActionLink("About", "Index", "About")</li>
        <li class="@(controllerAction == "HomeContact" ? "active" : "" )">@Html.ActionLink("Contact", "Contact", "Home")</li>
    </ul>

I think, that this is good because you don’t need to access “ViewContext.RouteData.Values” each time to get controller name and action name.

Method 26

My Solution to this problem is

<li class="@(Context.Request.Path.Value.ToLower().Contains("about") ? "active " : "" ) nav-item">
                <a class="nav-link" asp-area="" asp-controller="Home" asp-action="About">About</a>
            </li>

A better way may be adding an Html extension method to return the current path to be compared with link

Method 27

I did this:

Made a helper in menu partial view

 @helper RouterLink(string action, string controller)
{
    var IsActive = ViewContext.RouteData.Values["Controller"].ToString() == controller && ViewContext.RouteData.Values["Action"].ToString() == action;
    <text>href="@Url.Action(action, controller)" rel="nofollow noreferrer noopener"</text>if (IsActive){ <text>class="active"</text>}
}

Then used it in the anchor tag like this:

<li><a @RouterLink("Index","Home")>Home</a></li>

My application had no areas but it can also be included as another variable in the helper function. And I had to pass the active class to the anchor tag in my view. But li can also be configured like this.

Method 28

ASP.NET Core & Bootstrap 4 & AdminLte

[HtmlTargetElement("a", Attributes = "active-then")]
[HtmlTargetElement("a", Attributes = "asp-action")]
[HtmlTargetElement("a", Attributes = "asp-controller")]
public class AnchorActiveTagHelper : AnchorTagHelper
{
    public AnchorActiveTagHelper(IHtmlGenerator generator) : base(generator)
    {
    }

    [HtmlAttributeName("active-then")]
    public string ActiveWhen { get; set; }

    [ViewContext] [HtmlAttributeNotBound] public ViewContext ViewContextData { get; set; }

    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        base.Process(context, output);
        
        if (ActiveWhen == null)
            return;

        var currentController = ViewContextData.RouteData.Values["controller"].ToString();
        var currentAction = ViewContextData.RouteData.Values["action"].ToString();

        if (currentController.Equals(Controller) && currentAction.Equals(Action))
        {
            if (output.Attributes.ContainsName("class"))
            {
                output.Attributes.SetAttribute("class", $"{output.Attributes["class"].Value} active");
            }
            else
            {
                output.Attributes.SetAttribute("class", "active");
            }
        }
    }
}

And

@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@removeTagHelper Microsoft.AspNetCore.Mvc.TagHelpers.AnchorTagHelper, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, YourProject.PlatformExtensions

Usage

<li class="nav-item">
    <a asp-controller="Home" asp-action="Index" class="nav-link" active-then="active">
       <i class="nav-icon fas fa-home"></i>
       <p>Home</p>
    </a>
</li>

Thanks @WoIIe and @Shahab


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x