ASP.NET MVC tab-based navigation

First of all this is not one of those JavaScript tab navigation scripts. Actually we are going to use no JavaScript.

Each tab is going to be linked to an ASP.NET MVC controller action. This is how end result is going to look like:

ASP.NET MVC Tabbed Navigation

Source code for this article can be accessed from github.com/atashbahar/mvc-tab-nav.

So how exactly this works?

We have a HTML helper method named SimpleNav that renders the HTML to the master page. This is how it is called:

<div id="menubar">
    <%= Html.SimpleNav(new[] {
        new SimpleNavItem{Text="Home", Action="Index", Controller = "Home"},
        new SimpleNavItem{Text="Blog", Action="Index", Controller = "Blog", GetSelected = ((a, c) => (c == "Blog"))},
        new SimpleNavItem{Text="About", Action="About", Controller = "Home", GetSelected = ((a, c) => c == "Home" && a == "About")},
        new SimpleNavItem{Text="Contact", Action="Contact", Controller = "Home", GetSelected = ((a, c) => c == "Home" && a == "Contact")}
    }) %>  
</div>

The code for this helper method is very straightforward. It simply generates an unordered list of links:


public static string SimpleNav(this HtmlHelper html, IEnumerable<SimpleNavItem> navItems)
{
    var urlHelper = new UrlHelper(html.ViewContext.RequestContext);
    string controller = html.ViewContext.RouteData.Values["controller"].ToString();
    string action = html.ViewContext.RouteData.Values["action"].ToString();

    TagBuilder ul = new TagBuilder("ul");
    ul.AddCssClass("clearfix");

    StringBuilder listBuilder = new StringBuilder();
    TagBuilder li = null;
    TagBuilder a = null;
    foreach (var item in navItems)
    {
        a = new TagBuilder("a");
        a.Attributes.Add("href", urlHelper.Action(item.Action, item.Controller));
        a.InnerHtml = item.Text;

        li = new TagBuilder("li");
        if (item.GetSelected != null && item.GetSelected(action, controller))
            li.AddCssClass("sel");
        li.InnerHtml = a.ToString();

        listBuilder.Append(li.ToString());
    }

    ul.InnerHtml = listBuilder.ToString();

    return ul.ToString();
}
public class SimpleNavItem
{
    public string Text { get; set; }
    public string Action { get; set; }
    public string Controller { get; set; }
    public Func<string, string, bool> GetSelected { get; set; }
}

The interesting part of the above code may be GetSelected which is an anonymous method. You might want a tab gets highlighted on certain conditions for example highlight the Blog tab for all Actions of the related Controller. The method accepts two Strings which are name of the current Controller and Action and returns a Boolean which indicated if the tab should be highlighted or not.

The final step which I like the most is to make it pretty. By using a simple background image and a small amount of CSS magic you can easily achieve this:

#menubar {
    border-bottom: solid 3px #8CC740;
    padding-left: 10px;
}
#menubar li {
    display: inline;
}
#menubar li a {
    float: left;    
    line-height: 21px;
    width: 80px;
    margin-right: 1px;
    background: url(tabs.gif) no-repeat 0px 0px;    
    color: #444;    
    text-align: center;
    text-decoration: none;
}
#menubar li a:hover {
    background-position: 0px -22px;
    text-decoration: none;
}
#menubar li.sel a {
    background-position: 0px bottom;
    color: #fff;
}

This may not be the most complete solution but it has helped me in so many projects. Hopefully it does the same for you.