Twitter Bootstrap navigation with automatic active class for current page usng ASP.NET MVC

I’ve been playing around some more with Twitter Bootstrap and MVC and wanted to create a top level menu where the active class was added automatically to the item corresponding to the current page. Initially I had an action link inside the list item tag, but as the active class needs to be added to the list item so I decided to create an extension method to generate the entire item for me.

Here is how the markup looks straight from one of the bootstrap samples:

<ul class="nav">
  <li class="active"><a href="#">Home</a></li>
  <li><a href="#about">About</a></li>
  <li><a href="#contact">Contact</a></li>
</ul>

And here is my mark up using my MenuLink HTML helper:

<ul class="nav">
    @Html.MenuLink("Home", "Index", "Home")
    @Html.MenuLink("Clients", "Index", "Client")
    @Html.MenuLink("Projects", "Index", "Project")
</ul>

It’s use is just like an action link, but internally it checks the current controller and action and returns the link inside an li tag with the active class added for the current page. Here is the code:

public static MvcHtmlString MenuLink(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName)
{
    var builder = new TagBuilder("li");

    var currentAction = htmlHelper.ViewContext.RouteData.GetRequiredString("action");
    var currentController = htmlHelper.ViewContext.RouteData.GetRequiredString("controller");

    if (controllerName == currentController && actionName == currentAction)
    {
        builder.AddCssClass("active");
    }

    builder.InnerHtml = htmlHelper.ActionLink(linkText, actionName, controllerName).ToHtmlString();

    return new MvcHtmlString(builder.ToString());
}

The code is fairly self explanatory; first I use the TagBuilder class to create my list item element. Next I check the current controller name and action name against those passed into the method, if they match I add the active class to the builder. The InnerHtml of the list item is set by calling ActionLink.

Bootstrap Top Navigation

I also want to use the same helper for sub-level navigation like in the image below.

Bootstrap Sub Navigation

This worked fine for my List Clients menu item as it used the same action and controller as the Clients item in the top navigation, but as soon as I clicked Add Client, Clients was deselected in the top navigation as the action didn’t match. To overcome this I added an optional Boolean parameter to my extension method called isRootLevel. When this is true, it only compares the controller ignoring the current action. For my top navigation I want to set this to true so that no matter which item I choose in the sub navigation it will still highlight Client in the top navigation. The extension method has been updated like so:

public static MvcHtmlString MenuLink(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName, bool isRootLevel = false)
{
    var builder = new TagBuilder("li");

    var currentAction = htmlHelper.ViewContext.RouteData.GetRequiredString("action");
    var currentController = htmlHelper.ViewContext.RouteData.GetRequiredString("controller");

    if (controllerName == currentController && (actionName == currentAction || isRootLevel))
    {
        builder.AddCssClass("active");
    }

    builder.InnerHtml = htmlHelper.ActionLink(linkText, actionName, controllerName).ToHtmlString();

    return new MvcHtmlString(builder.ToString());
}

My mark up for the top navigation now needs to be updated:

<ul class="nav">
    @Html.MenuLink("Home", "Index", "Home", true)
    @Html.MenuLink("Clients", "Index", "Client", true)
    @Html.MenuLink("Projects", "Index", "Project", true)
</ul>

And that’s it!

Bootstrap top and sub navigation

Posted on by Joe in ASP.NET, C#, MVC

One Response to Twitter Bootstrap navigation with automatic active class for current page usng ASP.NET MVC

  1. joel

    Great solution. Thanks!

Add a Comment