Implementing Incremental Navigation with ASP.NET
By Andrew Wrigley
Introduction
Traditionally, website navigation has been focused on minimizing the number of clicks required to open a given page. However, this goal has nothing to do with the real purpose of navigation, which is to make finding information easy, consistent, and transparent to the user. Also, as websites get bigger, traditional navigation controls such as drop-down menus or tree views become impractical. Faster Internet connections and larger screen sizes now allow developers to experiment with new styles of navigation.
This article shows how to implement incremental navigation, which is a style of navigation where users find information by clicking through a series of lightweight pages, with each click resulting in a small, but highly visible change to the navigation user interface. It differs from traditional drop-down menu navigation in that incremental navigation limits the amount of new choices available to just the next level in the sitemap hierarchy.
I've created a customizable framework for implementing this sort of navigation scheme named Theseus, which you can download from the end of this article. Underneath the
covers, Theseus uses ASP.NET's SiteMap
class and the configured sitemap provider
to implement the incremental navigation. This article starts with an overview of incremental navigation and then goes on to examine how to use Theseus to implement
such a navigation scheme in your website. Read on to learn more!
The Benefits of Incremental Navigation
Modern websites increasingly use an incremental navigation paradigm: users find information by clicking through a series of lightweight pages, with each click resulting in minimal but highly visible changes to the navigation controls. Incremental navigation differs from traditional drop-down menu navigation in that it limits the amount of new choices available to just the next level in the hierarchy of information. It also highlights the "current branch" (or "breadcrumb") in the hierarchy, where the current branch is the path that the user has followed to reach the current node. Highlighting the current branch shows users how they got to where they are and how they can retrace their steps. This is how our brains work, so users find this kind of navigation intuitive. It also minimizes the markup that gets rendered with each request.
On the contrary, drop-down menus force users to think in terms of hierarchies of which they may have no previous knowledge. They also offer all available choices at all times thereby maximizing the rendered markup, but offer little or no visual indication of the current branch. As a result, a user's sense of frustration and confusion increases exponentially with the number of levels in the hierarchy of information. Now why would you do that to your users?
A Working Example of Incremental Navigation
To see incremental navigation in action, take a look at the The Encephalitis Society website. This site consists of hundreds of pages nested in a hierarchy that is up to five levels deep. Visitors to this site vary from people affected by Encephalitis - which can cause severe brain injury - to medical professionals. As a result, a consistent navigation is central to the usability of this website.
The navigation on the Encephalitis Society website has three main elements:
- The site tabs,
- The section menu, and
- The side menu
The Structure of the Navigation System

The site tabs are the series of tabs along the top of the page - Home, Information, The Society, and so forth. Selecting a site tab takes the user to the landing page for that tab. It also highlights the site tab and displays the subelements in the section menu. The screen shot below shows the navigation UI after the user has selected the Information tab. The background and foreground colors of the site tabs makes it clear that the Information tab has been selected.
A Tab Selected From the Site Tabs

The user can drill down further into the site by clicking on one of the links in the section menu - The Illness, Recovery and Rehabilitation, and so on. Clicking on one of these section menu options takes the user to a new page and highlights the selected section menu option by bolding its text (see the screen shot below). It also loads any subelements of the section menu into a side menu.
An Item Selected from the Section Menu

The side menu displays all remaining sitemap nodes for the selected section menu option. In the following screen shot the user has expanded the What is Encephalitis option from the side menu and clicked on the Causes of Encephalitis entry. This displays a page that details the causes of the encephalitis. Note that the navigational user interface clearly indicates the current branch to the user. Through the use of colors and bolded text it is apparent that the user is viewing the Causes of Encephalitis page, which is a subelement of What is Encephalitis, which is a subelement of The Illness, which is under the Information section.
A Page Selected from the Side Menu

An incremental navigation system obviates the need for a breadcrumb control (the ASP.NET SiteMapPath control) because it is immediately clear how the user arrived at any page: the current branch is highlighted in an obvious way. The user is not forced to think hierarchically and so navigating the site is intuitive and easy.
Before continuing on, take a moment to visit The Encephalitis Society website to get a good feel of how the navigation system
works. While it may not be apparent, the navigation system on The Encephalitis Society website uses ASP.NET's sitemap system and navigational Web controls. The navigational
sections of the site are defined in the Web.sitemap
file. The site tabs and section menu are implemented using the ASP.NET Menu control; the side menu is
implemented via the ASP.NET TreeView control.
Building an Incremental Navigation Framework
When designing the incremental navigation for The Encephalitis Society website I wanted to do so using a componentized, reusable model so that I (or others) could plug such a navigation system into other ASP.NET websites. I ended up creating a framework (written in C#) that I named Theseus after the mythological slayer of the Minotaur in the Labyrinth. The Theseus framework and a demo web application are available for download at the end of this article.
Theseus is packaged into five files. The names are pretty self explanatory:
- Two User Controls (
.ascx
files) provide the UI and plug into your master page(s):/Controls/Menus/TopMenu.ascx
/Controls/Menus/SideMenu.ascx
- Two classes contain the code that powers Theseus:
/App_Code/Library/Theseus/TheseusClass.cs
/App_Code/Library/Extensions/SiteMapExtender.cs
- Finally, there is a class that provides the structure to ensure that the Theseus boilerplate code is available to all pages in your website:
/App_Code/Library/BasePages/TheseusPage.cs
Web.sitemap
file; however, you could plug in an alternate sitemap provider and use Theseus the same. What's more, the demo application uses the
CSS Friendly Menu and TreeView control adapters and uses CSS for styling. The CSS Friendly adapters alter the markup emitted by
ASP.NET's TreeView and Menu controls to use <ul>
's rather than <table>
s, and focuses on defining style information through CSS classes
rather than through the HTML elements' style
attributes. For more on the CSS Friendly Control Adapters, see http://www.asp.net/CssAdapters.
Nuts and Bolts
The site tabs and the section menu are both implemented using ASP.NET Menu controls and are packaged into the
TopMenus.ascx
file. The side menu is implemented
using an ASP.NET TreeView control and is packaged into the SideMenu.ascx
file. The Menu controls and the TreeView control are declaratively bound to their own
SiteMapDataSource controls.
Take a look at the pertinent markup for SideMenu.ascx:
<asp:Panel ID="pnlSideMenu" runat="server" CssClass="SideMenuWrapper">
|
The markup for TopMenus.ascx
is even simpler. You can view it by downloading the demo available at the end of this article.
The SideMenu.ascx
code behind file, shown below, is fairly straightforward, too. Note that the code to populate the side menu is contained within the Theseus
framework. The SideMenu.ascx
User Control merely hands over the TreeView control to the Theseus framework via a call to the LoadSideMenu
method.
The LoadSideMenu
method then adds the nodes to show in the side menu. The SetNodeSideMenu
method, called from the DataBound
event
handler, expands the necessary nodes in the TreeView. We'll examine the inner workings of both these method later on in this article.
public partial class SideMenu : System.Web.UI.UserControl
|
In addition to populating and expanding the side menu as needed, the Page_Load
event handler also displays the title of the section menu node in the
lblSideMenuHeader
Label control. This Label control is not part of the Theseus framework, but is rather an example of how to add additional, customized
content to the TopMenus.ascx
and SideMenu.ascx
User Controls to conform to any specific requirements for the site.
A Custom Base Class for All Pages: TheseusPage
The Theseus framework is powered by the class
TheseusClass
. This class contains methods like LoadSectionMenu
and LoadSideMenu
, and is
used by the TopMenus.ascx
and SideMenu.ascx
User Controls to populate the appropriate content into their navigation user interface elements. Since
this class is used by every page in the website, I created a custom base page class named TheseusPage
that has a property named Theseus
that returns
an instance of the TheseusClass
class. Consequently, all ASP.NET web pages that use the Theseus framework need to inherit from this custom base class.
If you create your ASP.NET pages where the markup and code is in the same file then you can make TheseusPage
the base class to all your pages by using the
pageBaseType
attribute of the <pages>
section in Web.config
:
<pages pageBaseType="Wingspan.Web.Core.TheseusPage">
|
If you have your ASP.NET pages' markup and code sections separated into two files then you will need to go through each code behind file and changing the base class that
your pages inherit from System.Web.UI.Page
to Wingspan.Web.Core.TheseusPage
(or whatever you call your custom base class):
public partial class MyPage : Wingspan.Web.Core.TheseusPage
|
For more information on using a custom base page class and its benefits, refer to Using a Custom Base Class for your ASP.NET Pages' Code-Behind Classes.
The Engine That Powers Theseus: TheseusClass
The Theseus framework is powered by
TheseusClass
, which has two core tasks:
- Determining what items in the sitemap need to be displayed in the top menus and side menu given the page being visited, and
- Determining the current branch so that we know what items in the navigation user interface need to be highlighted.
SiteMap
class. The
SiteMap
class is part of the ASP.NET framework and provides an "in memory representation of the navigation structure for a site, which is provided by one or more site
map providers."
The most important property of the SiteMap
class is CurrentNode
, which represents the SiteMapNode
object in the sitemap structure that corresponds to the page being currently requested.
SiteMapNode cn = SiteMap.CurrentNode;
|
If the page being requested is not represented by a node in Web.sitemap
then CurrentNode
returns null
. In this case, Theseus goes into
its "inactive" state and shows only the Site Menu with no tabs highlighted.
The other important SiteMap
property is RootNode
, which returns the SiteMapNode
that is the root of the sitemap hierarchy. The
CurrentNode
and RootNode
properties are used to determine the current branch, as the current branch is, by definition, the path between the
current node and the root.
The SiteMapExtensions
Class
Theseus needs to calculate the current branch as a
List
of SiteMapNode
objects. It would have been nice if Microsoft had implemented a property
such as SiteMap.CurrentBranch
, but they didn't. Fortunately, this List
can be computed with only a few lines of code. In addition to computing the
current branch List
, there are a number of other sitemap-related tasks that Theseus needs to perform that are not built into the SiteMap
class. These
methods and properties are grouped into a class named SiteMapExtensions
; this class is used from the TheseusClass
class, which includes a member
variable named SiteMapExtender
of type SiteMapExtensions
.
namespace Wingspan.Web.Core
|
The code in SiteMapExtensions
class is pretty straight forward and well documented. There is the CurrentBranch
property, which returns the List
of SiteMapNode
s that makes up the current branch; a CurrentNodeLevel
property, which returns the level of the current node in the sitemap hierarchy;
and a handful of methods.
Examining TheseusClass
In Detail
To get a better understanding of how Theseus works, I'd like to explore the code in
TheseusClass
that relates to the TreeView control (the Side Menu) in detail.
Recall that the SideMenu.ascx
User Control is responsible for displaying the side menu using a TreeView control. Its Page_Load
event handler populates
the TreeView with the appropriate nodes based on the requested page by calling the TheseusClass
's LoadSideMenu
method, passing in both the
SiteMapDataSource (dsMenu3
) and the TreeView (tvMenu3
) controls defined in the User Control's markup portion:
private TheseusClass Theseus;
|
The LoadSideMenu
method starts by getting a reference to the node in the Section Menu that has been selected and storing it in a variable named node2
.
(Recall that the Side Menu displays the descendant nodes of the SiteMapNode
selected from the Section Menu.) This selected Section Menu SiteMapNode
is
retrieved by calling the SiteMapExtension
class's CurrentBranchNode
method, passing in the SectionMenuLevel
variable. This
SectionMenuLevel
variable is an integer value that indicates what level of the sitemap hierarchy was rendered in the Section Menu. In our sample, this value is
set to 2, but can be customized via the TheseusClass
's constructor.
public void LoadSideMenu(SiteMapDataSource dsMenu3, TreeView tv)
|
Now that we have the selected Section Menu node we check to see if it is null
. It would be null
if the selected Site Tab is a leaf node. For example,
if the page being requested was the Home Page then node2
would be null
. If node2
is not null
, then we need to ensure that
the Side Menu TreeView control (the tv
parameter) is made visible, that it is expanded to the correct depth, and that it shows the descendant nodes
of node2
.
public void LoadSideMenu(SiteMapDataSource dsMenu3, TreeView tv)
|
Note that we set the dsMenu3
SiteMapDataSource control's StartingNodeUrl
property to the URL of the selected Section Menu node (node2.Url
).
Because the SiteMapDataSource has had its ShowStartingNode
property set to false in the User Control markup only the children nodes of node2
will be returned.
The TreeView's ExpandDepth
property indicates how many levels of TreeView nodes are expanded, by default. This value is determined by the level of the current
node in the sitemap hierarchy, which is available via the CurrentNodeLevel
property in the SiteMapExtensions
class. That's all we need to do to
load the Side Menu. However, there still remains one important part in rendering the Side Menu: we need to highlight the appropriate nodes in the TreeView based on the
current branch.
Highlighting the appropriate nodes in the TreeView can only happen once the data has been bound to the control. The TreeView's DataBound
event is raised after
the data has been bound to the TreeView. Therefore, it makes sense to create an event handler for the DataBound event and to put the logic there for selecting the appropriate
TreeView nodes. This event handler is defined in the SideMenu.ascx
User Control and simply calls the TheseusClass's SetNodeSideMenu
method, passing
in the TreeView control.
protected void SideMenu_DataBound(object sender, EventArgs e)
|
The SetNodeSideMenu
method starts by collapsing all of the TreeView nodes. This guarantees that only the nodes on the current branch will be expanded, which
is what we want. Next, the method checks to see if there is a selected node in the TreeView; if so, that node is expanded. If there is no selected node then the TreeNode that
represents the SiteMap.CurrentNode
is selected. Finally, the selected node's parent is expanded to guarantee that the selected node will be visible on the
rendered page.
The SetNodeSideMenu
method follows:
public void SetNodeSideMenu(TreeView tv)
|
The most common scenario is that there was no selected node. In this case the SetSelectedTreeNode
method gets called. This SetSelectedTreeNode
method
is in charge of selecting the TreeNode that represents the SiteMap.CurrentNode
SiteMapNode
object. The only complication with this code is to map
SiteMap.CurrentNode
to one of the TreeNodes. To do that, I use the TreeView's FindNode
method, and the whole problem is reduced to building the
ValuePath
to the current node:
private void SetSelectedTreeNode(TreeView tv)
|
The eagle eyed reader may have noticed that this code only selects the current node. How do I make the other nodes along the current branch aware that they should display in bold?
The answer is that I don't need to do anything. Using the CSS Friendly Adapters causes the nodes along the current branch to all have a CSS class of
AspNet-TreeView-ChildSelected
. Therefore, I can set these display-related settings in the CSS definition without having to write any C# code. For more on this
look at the CSS in the ~/App_Themes/ws/SideMenu.css
file.
Building the CurrentNode
's ValuePath
is really simple because we can build it from the CurrentBranch
property of the
SiteMapExtender
object. I have packaged the code that does this into the SiteMapExtensions
class's CurrentNodeValuePath
method:
public string CurrentNodeValuePath(int startFromLevel)
|
The code for CurrentNodeValuePath
is pretty simple, you just need to be careful with the startFromLevel
parameter to make sure you calculate the
ValuePath
from the right place.
All we need now is the code for the ExpandSideMenu
method. This method starts from the CurrentNode
and works back up the tree using the
TreeNode
object's Parent
property, expanding the parent at each step.
private void ExpandSideMenu(TreeView tv)
|
Conclusion
Many users (and clients) hate drop down menus. Users hate thinking hierarchically, which is what drop down menus force them to do.
From a technological perspective, drop down menus are a hangover from the days of small screens and dial up Internet connections and if you, as the developer, are not yet convinced of the benefits of incremental navigation, just think of a website where the information is nested in a hierarchy of pages that is five levels deep. Drop-down menus, anyone? No, I didn't think so.
The Theseus framework is just as easy to use in your websites as a Menu control. Its User Interface is highly customizable and it renders standards compliant markup that is much more optimized than traditional drop down menus. Your users no longer need a ball of string to kill the Minotaur.
Happy Programming!
Attachments
Further Reading
SiteMap
class technical docs
A Word About The Encephalitis Society
I decided to write this article in March 2009 after watching Red Nose Day coverage on the BBC. Red Nose Day is a UK thing, where you are encouraged to do something fun for charity.
My first ever client was Elaine Dowell, chairperson of the Encephalitis Society. Encephalitis is an inflammation of the brain, caused by an infection. It can cause severe acquired brain injury, even death. Many people recover pretty much completely, but it can also lead to terrible long term consequences and suffering for the people affected, as well as for their family and caretakers. When Elaine's son got Encephalitis, a rare but all too often devastating syndrome, she decided to do something. Ten years later, she is still doing just that.
The story that best sums Elaine up is this one: I was in the Society offices one day discussing changes to the website. A group of new regional reps turned up for a meeting with the regional coordinator whilst Elaine and I went to war over a pixel here, a hue there. As the reps were leaving one of them, a middle aged lady, hung back. When the others had left, she asked: "Is Elaine Dowell here?" The receptionist brought her over to meet Elaine. "You are my family's hero," said the new rep. "We would never have survived without you."
Hopefully, you won't ever need a hero to save your family. But if this article helped you in your daily work then go do the right thing - visit The Encephalitis Society website and click the Make a Donation button. You will feel really good and your nose will turn red. The more you donate, the redder it will go. If you don't believe me, just click the Make a Donation button and see for yourself. Make sure you have a mirror handy.