ASP.NET Menu: Sliding Doors of CSS

December 6, 2008

IntroductionWeb Development

The purpose of this article is to create a slick looking and easy to use menu for an ASP.NET enabled website. In order to accomplish this we’ll use the standard functionality of the ASP.NET Menu web control and enhance the look purely by using Cascading Style Sheets (CSS).

For those of you familiar with CSS the title of this article will surely ring a bell. The CSS used to enhance the look and feel of the ASP.NET Menu control is decribed in a widely known article on A List Apart, entitled “Sliding Doors of CSS“.

The CSS used to improve the look and feel of the menu is thoroughly explained in the article on A List Apart. Credit when credit is due. Thank Douglas Bowman for supplying us with the CSS. Be sure to read his article first if you are not familiar with it.

The focus of this article is on how to simulate such a menu in an ASP.NET environment. Let’s get started…

Table Of Contents


Let’s fire up Visual Studio 2008 and create a new project using the ASP.NET Web Application project template. This template will automatically add a default web form appropriately named “Default.aspx”. Open it in the editor and add the Menu control from the Toolbox which you can find under the Navigation tab. If you run the website now you’ll wind up staring at a blank page. For the menu to display anything it first has to be bound to some data.

The easiest way to define data for the menu control to use and enable the visitors to navigate through the website is to bind it to a site map. Add a new site map item to the project using the proposed name of “Web.sitemap”. The site map is an Xml file that organizes the pages of the site in a hierarchical manner. An added advantage is that it is automatically referenced by the SiteMapDataSource control.

Next add some pages to the sitemap as displayed in the listing below.

Listing 1 – Web.sitemap

<?xml version="1.0" encoding="utf-8" ?>
<siteMap xmlns="" >
    <siteMapNode url="" title=""  description="">
      <siteMapNode url="Default.aspx" title="Home"  description="Take me back to the dasboard" />
      <siteMapNode url="Products.aspx" title="Products"  description="Browse our catalog" />
      <siteMapNode url="Download.aspx" title="Download"  description="Download neat stuff" />
      <siteMapNode url="Forum.aspx" title="Forum"  description="Ask questions on our forum" />
      <siteMapNode url="Contact.aspx" title="Contact"  description="Contact us" />

Now add a SiteMapDataSource control to the page and set the DataSourceID property of the menu control to the Id of the data source. Also set the Orientation property of the menu control to horizontal as it defaults to vertical. Last but not least set the ShowStartingNode property of the SiteMapDataSource to false. If you don’t do this only the root node will be displayed and we don’t want to include this base node in the menu. Your code should now resemble the code displayed in Listing 2.

Listing 2 – Default.aspx

<asp:Menu ID="Menu1" runat="server" DataSourceID="SitemapDataSource1" Orientation="Horizontal"></asp:Menu>
<asp:SiteMapDataSource ID="SiteMapDataSource1" runat="server" ShowStartingNode="False" />

If you view the page in a browser now you should see a functional, yet boring menu.

Figure 1 – Plain horizontal menu

ASP.NET Menu control in action

ASP.NET Menu control in action

Top of page

CSS Friendly Adapters

Before we can start applying CSS to the menu there is another issue that needs to be addressed first. If you take a look at the resulting HTML code that is generated when you request the default.aspx page you’ll notice that the menu control does not generate the most flexible HTML code. By default it wraps each menu item in a table. This does not lend itself for easily applying CSS. It would be better if the Menu control generated an unordererd list which contains all the menu items.

Luckily the generated HTML can be adjusted by using control adapters. Control adapters allow you to render the HTML you prefer. Thankfully such control adapters are readily available on CodePlex. The CSS Friendly Control Adapters kit provides pre-built control adapters, including one for the ASP.NET Menu control.

To use the CSS Friendly Control Adapters follow these steps:

  • Download the latest release. Download the version containing the source code and not the compiled assembly.
  • Add the downloaded project to your solution.
  • Download the CSSFriendlyAdapters.browser file and add it to the App_Browsers folder of your ASP.NET Website project.

It is necessary to use the source code and compile the CSSFriendly.dll assembly ourselves because we need to tweak some of the CSS used by the adapters later on in this article.

When adding the CSSFriendly project to your solution the Visual Studio Conversion Wizard will popup. Just execute the conversion, everything should go smoothly. When the conversion has completed all that remains is to add a reference to the CSSFriendly project from the ASP.NET Website project.

Just run the website and take a look at the generated HTML code now.

Listing 3 – CSS Friendly HTML code

<div class="AspNet-Menu-Horizontal" id="Menu1">
    <ul class="AspNet-Menu">
        <li class="AspNet-Menu-Leaf  AspNet-Menu-Selected">
            <a href="/Default.aspx" class="AspNet-Menu-Link  AspNet-Menu-Selected" title="Take me back to the dasboard">Home</a>
        <li class="AspNet-Menu-Leaf">
            <a href="/Products.aspx" class="AspNet-Menu-Link" title="Browse our catalog">Products</a>
        <li class="AspNet-Menu-Leaf">
            <a href="/Download.aspx" class="AspNet-Menu-Link" title="Download neat stuff">Download</a>
        <li class="AspNet-Menu-Leaf">
            <a href="/Forum.aspx" class="AspNet-Menu-Link" title="Ask questions on our forum">Forum</a>
        <li class="AspNet-Menu-Leaf">
            <a href="/Contact.aspx" class="AspNet-Menu-Link" title="Contact us">Contact</a>

Things are looking up now.

Remark: The CSSFriendlyAdapters.browser file allows you to specify which CSS Friendly control adapters should be used. I make a habbit of commenting all of the adapters except the ones I want to use. This way no other controls are “adapted” and they’ll keep generating the default HTML.

Top of page

Styling The Menu

As you can see from the code displayed in the listing above the adapter for the menu control automatically injects the necessary CSS classes for the <ul>, <li> and <a> tags. This saves us the trouble from having to define these.

It is also quite common for a single page to contain more than a single adapter control such as a menu. If you want a distinct look and feel for each control then set the CssSelectorClass for the adapted control. For instance, you might set the value of the CssSelectorClass property as follows:

Listing 4 – CssSelectorClass property

<asp:Menu ID="Menu1" runat="server" DataSourceID="SitemapDataSource1" Orientation="Horizontal" CssSelectorClass="PrettyMenu">

The result is that the HTML code generated by the adapted control will be contained within a new layer (<div>).

Listing 5 – Wrapping the generated HTML code

<div class="PrettyMenu" id="Menu1">
<!-- Other HTML code -->

Note that this property is specific to the CSS Friendly Adapters. It is a custom (expando) attribute which you can set for the controls supported by this library. It you require more information about the way the Friendly Adapters work, then please consult the following links:

With the CssSelectorClass generating a separate layer (<div>) around the menu and the automatically injected CSS classes in place we are finally ready to commence styling the menu.

The CSS used is simular to that of the A List Apart article. As mentioned before the focus of this article isn’t on the structure of the CSS but rather on how to apply it to the ASP.NET Menu control in order to obtain a neat looking tabular menu. The finished result can be seen in Figure 2.

Figure 2 – The Finished result

Fancy menu in action

Fancy menu in action

On the download page you can find the source code for this article. It contains the style sheet and the necessary images. Just perform the following steps to recreate the finished result:

  • Add a Theme called “Default” under the ASP.NET folder Asp_Themes
  • Add the existing images found in the compressed file containing the source code for this article under the newly create theme folder
  • Add a style sheet called global.css to the Default theme
  • Copy the contents of my global.css style sheet and paste them into your style sheet
  • Open the web.config file and set the Theme property for the <Pages> node to Default. (See Listing 6)

Listing 6 – Web.config excerpt

  <!-- ... -->
  <pages theme="Default">
    <!-- ... -->
  <!-- ... -->

The CSS used in my solution is simular to that of the article on A List Apart, but there are some changes. Mainly the changes correlate to the CSS structure applied by the CSS Friendly Adapters.

In order to apply the CSS the correct structure needs to used. When styling a control whose HTML is adjusted by a Friendly Adapter I find it handy to use diagrams mentioned in the white paper. These diagrams clearly show you how the CSS is structured.

You can find the diagram for the menu control here.

Top of page

Sub Menu

One question I frequently came accross on a lot of forums is how to implement a horizontal sub menu which changes when the user selects a different tab from the top level menu. To create this we first need to adjust our site map.

Listing 7 shows the adjusted site map.

Listing 7 – Web.sitemap with “sub menu items”

<?xml version="1.0" encoding="utf-8" ?>
<siteMap xmlns="" >
    <siteMapNode url="" title=""  description="">
      <siteMapNode url="Default.aspx" title="Home"  description="Take me back to the dasboard">
        <siteMapNode url="About.aspx" title="About us" description="" />
        <siteMapNode url="Foo.aspx" title="Foo" description="" />
        <siteMapNode url="Bar.aspx" title="Bar" description="" />
      <!-- ... -->

For brevity’s sake Listing 7 only displays the sub menu items (nodes) for the Home node. Check out the Web.sitemap in the source code for the complete version. Now when you browse the website using this site map you’ll see the effect shown in Figure 3.

Figure 3 – Sub menu items

Sub menu items in action

Sub menu items in action

To disable this effect set the MaximumDynamicDisplayLevels property of the menu control to zero as shown in Listing 8.

Listing 8 – MaximumDynamicDisplayLevels property

<asp:Menu ID="Menu1" runat="server" DataSourceID="SitemapDataSource1"
          Orientation="Horizontal" CssSelectorClass="PrettyMenu"

Next add a second Menu and SiteMapDataSource control and set their properties as shown in Listing 9.

Listing 9 – Sub menu control

<asp:Menu ID="Menu1" runat="server" DataSourceID="SitemapDataSource1"
    Orientation="Horizontal" CssSelectorClass="PrettyMenu"
<asp:Menu ID="Menu2" runat="server" DataSourceID="SitemapDataSource2"
    Orientation="Horizontal" CssSelectorClass="PrettySubMenu">
<asp:SiteMapDataSource ID="SiteMapDataSource1" runat="server" ShowStartingNode="False" />
<asp:SiteMapDataSource ID="SiteMapDataSource2" runat="server" StartingNodeOffset="1" ShowStartingNode="False" />

We basically tell the second menu that it should display the second level of nodes found in the site map and that it should not display the starting node which corresponds to the selected tab of the first menu.

Also the CssSelectorClass for the second menu is set to PrettySubMenu. The CSS for this menu is simular to the first menu. Download the source code if you want to check it out. Running the website now will give you this spiffy result.

Figure 4 – Styled sub menu items

Styled Sub Menu Items

Styled Sub Menu Items

Top of page

Finishing Up

One last issue needs to be resolved. In order to illustrate this issue the project needs to be reorganized.

First let’s add a master page to the project called Site.master. Move the code, the menus and data sources, from the Default.aspx page to the master page and place it just before the first content place holder in the body. Afterwards you can safely delete the Default.aspx page.

Now let’s add a few Web Content Form items to the project. Add Web Content Forms that correspond to the items of the first node of the site map and its sub nodes, namely:

  • Default.aspx
  • About.aspx
  • Foo.aspx
  • Bar.aspx

Be sure to choose Site.master as the master page for each of these web content forms. The other pages mentioned in the Web.sitemap are purely there for illustrative purposes.

Launch the site again, and navigate to the Foo page. This will reveal the issue.

Figure 5 – Selection issue

Which Top Level Menu is selected?

Which Top Level Menu is selected?

Because we have navigated to the bottom level in the site map the top level menu does not know which menu item it should mark as selected. We will need do some coding in the master page’s code behind in order to solve this.

Listing 10 shows you the necessary morsel of code.

Listing 10 – Selecting the correct top level menu item

namespace MenuWebApplication
    public partial class Site : System.Web.UI.MasterPage
        private static string ExtractBaseUrl(string url)
            return url.Contains("?") ? url.Remove(url.IndexOf('?')) : url;

        protected void Page_Load(object sender, EventArgs e)

            // Which node in the site map is currently selected?
            SiteMapNode currentNode = SiteMap.CurrentNode;
            if (currentNode != null)
                // Obtain the Url of the currently selected node's parent node.
                string parentUrl = String.Empty;
                SiteMapNode parentNode = currentNode.ParentNode;
                if (parentNode != null)
                    parentUrl = ExtractBaseUrl(parentNode.Url);

                // Obtain the Url of the currently selected node.
                string currentUrl = ExtractBaseUrl(currentNode.Url);

                // Iterate the top level menu tier.
                foreach (MenuItem menuItem in Menu1.Items)
                    // Compare the menu item's Url against the currently 
                    // selected node's Url or the Url of its parent.
                    string menuItemUrl = ExtractBaseUrl(menuItem.NavigateUrl);
                    if ((currentUrl == menuItemUrl) || (parentUrl == menuItemUrl))
                        // If either matches then mark the top level menu item as selected.
                        Menu1.Items[Menu1.Items.IndexOf(menuItem)].Selected = true;

Now you are free to select any of the sub menu items. It’s corresponding top level menu item will stay selected to give the visitor a visual clue as to where he currently is located within the website.

Figure 6 – Selection issue fixed

Sub Menu Item Tracking

Sub Menu Item Tracking

Top of page


It’s quite a bit of work to establish a fancy tabular menu with a context sensitive horizontal sub menu but in the end you wind up with a slick looking and user friendly menu.

I suggest that you implement such a menu in a user control and include that user control on your web site’s master page. In most cases one such menu will be used throughout the entire website.

If you have any comments or suggestions I’ll be glad to hear them.

Top of page


You can find the source code for this article on the Download page of this blog.

Top of page


39 Responses to “ASP.NET Menu: Sliding Doors of CSS”

  1. […] 7, 2008 ASP.NET Menu: Sliding Doors of CSS – 12/06/2008 December 6, 2008 Introduction The purpose of this article is to […]

  2. Ken Says:

    Awesome tutorial. Thanks much.

  3. Wout Says:

    Man, I ‘m planning to replace all my menus with those CSS friendly adapters for months. Never found the time to look into it.
    And now, you wrapped it up nicely in one article. This will save me so much time. Thanks !!

  4. […] Now, I just found this great article, on a blog of a personal friend,  that covers it all.  ASP.NET Menu: Sliding Doors of CSS […]

  5. Dave Says:

    Thank you so much for putting this together. I really appreciate the links back to codeplex and the additional link to the sliding doors. I am planning on implementing this approach – along with the horizontal submenu in my next project.

    I ‘discovered’ your blog by searching for “css sliding doors ASP.NET menu” in google. I plan on becoming an active reader of your work.

    Keep up the great work.

  6. Chris White Says:

    Thanks you for writing such a well thought out and helpful article. I was just starting to look at how I could get a tabbed effect and I was already using the CSSFriendlyAdapters and so this has helped out a lot.

  7. Chris White Says:

    Any tips on getting this to work in IE6 – I just see a tall gradient fill and no menu tabs under IE6.

  8. Christophe Says:

    Hrmm, if you look at the article I mention the following:

    “It is necessary to use the source code and compile the CSSFriendly.dll assembly ourselves because we need to tweak some of the CSS used by the adapters later on in this article.”

    …yet I forgot to say what that was later on. You need to tweak the CSS Friendly Adapters a bit to get it working correctly in IE6.

    Take a look at the following forum posts:

    This should help you out.

    PS: I tested a version of this menu in the just released IE8, seems to work nicely.



  9. Chris White Says:

    I used the following solution as contained in your second link above and I’ve tested the menu in IE6, IE7 and FF3 and it works in those browsers.

    ul.AspNet-Menu li
    float: left !important;
    /* height: 1% !important; */

    ul.AspNet-Menu li a,
    ul.AspNet-Menu li span
    height: 1% !important;
    width: 1%; /* */

  10. Chris White Says:

    Hi Christophe,

    One more thing – do you know of a way to prevent FF3 from outlining the anchor tag with a dotted box? The problem doesn’t occur in IE 6 or 7, but in FF3 it does. It wouldn’t be so bad, except that the box only outlines the right ‘door’ of the sliding doors and so looks offset when viewed in the tab.


  11. Christophe Says:

    Try a:focus {outline: none;} for the anchor tag.

    More information can be found in this forum post:

  12. matt Says:

    even after the Menu1.DataBind() I get error:

    foreach (MenuItem menuItem in Menu1.Items)

    –> Menu1.Items.Count == 0, so code fails.. help!

  13. Chris White Says:

    The a:focus solution works well. And in the context of the sliding doors solution you presented above, I ended up with a css rule like so:

    .PrettyMenu ul.AspNet-Menu a.AspNet-Menu-Link:focus

  14. Christophe Says:


    I don’t seem to experience the problem you mention. Check out the sample project I’ve mailed you.

    Also a friend of mine mailed me the following tidbit some time ago. It might be of use to you (or anybody else).

    Below the directive of a content page add the following line of code:

    <%@ MasterType VirtualPath=”~/Site1.master” %>

    Create the following function in the code behind of your master page:

    public void SetMainMenuTab(int tabIndex)
    if (Menu1 != null && Menu1.Items.Count > tabIndex)
    Menu1.Items[tabIndex].Selected = true;

    In a content page you can now call the SetMainMenuTab(…) function in the Page_PreRender(…, …) method.

    You can also execute it in the Page_Load(…, …) method, but you have to make sure that the Menu bindings are in order before the SetMainMenuTab(…) is called.

    E.g.: Master.SetMainMenuTab(0);

    If you prefer not to use the directive you can opt for a more “dirty” approach and cast the Master page yourself:

    E.g.: ((Site1)Page.Master).SetMainMenuTab(0);

    Code provided by Wauter Laureys,

  15. kåre Says:

    Thanks for an awesome submenu in

  16. SM Says:

    This is really nice work! Thanks for posting it.
    I have customized it for me.

    The only problem I am facing and trying to crack here is, I don’t want postback when user click on menu item but sub menu should appear asynchronously using AJAX.

    I saw many posts related but non helpful. The ASP.NET Menu control fully supports partial rendering. But need to know how.

    I will appreciate if you can help!


  17. cookster76 Says:

    I am having real problems getting the 2nd level to appear horizontally. I have done everything as per the tutorial but i get no second level on hover and when i click i just get redirected to the page defined in the url property (havent added master page yet, just using menu)

    everything works ok if i get the second level to appear vertically, it is only when i do the pretty sub-menu step that i hit trouble.

    Can anyone help?

    • DaCoder Says:

      @cookster76, I am trying to get the sub menu to show vertically could you tell me how you got that working.

      • cookster76 Says:

        Hi DaCoder,

        Just change the orientation setting in menu2 to vertical…at least i think thats what i did. I had a mishap with my laptop and lost the code, so I kind of left this project alone for a bit but am now revisiting. Will post again if i did something different.

      • cookster76 Says:

        hi please ignore my other comment. When i said i got the menu to orient vertically i meant that it works if i only have one menu control and the sub items display on hover over the top menu tabs. as soon as i add a second menu control it all stops working. I certainly cant get it to function as per the example 😦

  18. RRaveen Says:

    Dear Friends,

    I hope you are doing well. I have launched a web site and it is basically aimed C#,JAVA,VB.NET,ASP.NET,AJAX,Sql Server,Oracle,WPF,WCF and etc resources, programming help, articles, code snippet, video demonstrations and problems solving support. I would like to invite you as an author and a supporter. Looking forward to hearing from you and hope you will join with us soon.

    Please forward this email to all of your friends who are related IT. Send to us your feed about site also.

    Thank you

  19. Khan Says:

    I really appreciate your detailed article. I have same requirement to apply in MOSS website. IF you kindly guide/help me to apply same menu in MOSS website using MOSS SiteMapDataSource. Thanks and waiting of your help.

  20. Khan Says:

    Hi Everyone,

    Is any body kindly reply of my previous post. Thanks.

  21. Khan Says:

    Hi Everyone,

    Is this blog active. I have posted a query on September 7, 2009 at 22:35 and still no one even reply me. Kindly reply my query. Thanks

  22. Thanks! The tip on the not including the root node was crucial for me – all the other examples that I could find were related to a hardcoded menu and not one tied to the site map.

  23. Leendert Says:

    Thanks from me as well. Initially I dismissed your source code as it did not work in my ASP.NET 2.0 environment, but when I scrutinized your article again I saw the trick: a dummy root node, plus the ShowStartingNode=”False”. I consider this as a work-around, but it is the only acceptable work-around found so far (and I am looking for too much time).


  24. Martin Says:

    nice article, thanks.
    unfortunately the subMenu does not work properly for me.
    just like in figure 3, the menu is being displayed NEXT to the item selected.
    eg. hover over “Home” and menu entries are displayed below “Products”, which makes it impossible to select.

    i have downloaded the source and used it.
    have i missed something ?


  25. David Says:

    Hi Christophe,
    A few days ago, I made a start on trying to convert a standard Sliding Doors menu for use with the ASP:Menu control but with only limited success. Yesterday, I found your blog on this topic, which looked like just what I needed.

    However, I have no previous experience of using multiple projects in an ASP.NET website project and things are not working as expected.

    I have successfully added the CSS Friendly project to my Website Project solution (using VS2010). While both projects appear in the Solution Explorer the CSS Friendly folder does not appear to have been copied into my application. When I went through the Add Reference process, I noted that the reference was to the folder (on another disk) where I had originally downloaded the CSS Friendly files.

    When I view my Default.aspx page locally and look at the page source, I can see that the normal table structure of the menu has been replaced by a ul and set of li items. However the expected tab graphics don’t appear.

    On the assumption that this solution might only work on a real live website, I uploaded my code to my web server but then realised that I had no idea where to upload the CSS Friendly project (as its files are not physically part of my solution). The project reference that works on my own PC has no meaning on the web server. I would be very grateful if you (or anyone else) could clarify this issue.

    I also hit a separate problem when I later added the CSSFriendlyAdapters.browser file to my App_Browsers folder. This causes a Parser Error Message: Could not load type ‘CSSFriendly.MenuAdapter’.

    Any guidance would be much appreciated.


  26. Satish Says:


    you might wanna try:

    – Creating new project of type ‘library’ in existing solution and once created copy over all folders and files under this project in same hierarchy like CSSFriendly project. Then include each folder and file by right click -> Include. Add all references similar to CSSFriendly project and you should be good to go.

  27. David Says:

    Hi Satish,
    I added a new project called MyLibrary and ensured that it contained the same contents as the CSS Friendly project (as viewed from the Solution Explorer of VS2010). When I then looked at the results in Windows Explorer, I could see that this new project had been added as a subfolder of the original Project folder. However, I am developing a Website Project, not a Web Application Project. The project folder is not uploaded to the web server and only seems to serve a purpose in the local machine.

    The end result is that I still cannot see any structure for locating the CSS Friendly files on the web server. Am I missing something here?

  28. David Says:

    Subsequent to my previous post, I came to the conclusion that what I really needed to do was find a way of compiling the CSSFriendly dll file. However, I had no idea how to do this as there is no guidance on this topic for ASP.NET newbies either on this blog or on the Codeplex page.

    After some kind assistance from Christophe, I have now successfully compiled this dll. In case it helps someone else, the process was as follows.

    1. Opened the ‘Web’ sample website supplied as part of the CSS Friendly download from Codeplex (though I first renamed it SampleCSSFriendlyWebsite). I noted that this solution does not yet have a Bin folder.

    2. Right clicked on this solution folder in VS2010 and selected Add/Existing Project. I then browsed to CSSFriendly.csproj, contained in the ‘CSSFriendly’ folder downloaded from Codeplex.

    3. Accepted the request to convert the project to the latest version. This ran without error and both projects were now visible in the Solution Explorer, i.e. SampleCSSFriendlyWebsite and CSSFriendly.

    4. Right clicked on my SampleCSSFriendlyWebsite project and selected Add Reference…

    5. The Add Reference dialogue box then appeared with the Projects tab selected and CSSFriendly listed in the box. I clicked OK to add this reference.

    6. Right clicked the solution node in the Solution Explorer and selected “Rebuild Solution”.

    7. A Bin folder was created automatically in SampleCSSFriendlyWebsite. This folder contained CSSFriendly.dll.

  29. David Says:

    I hit more problems when trying to add this Sliding Doors menu to a couple of existing sites. Among other issues, error windows popped up as soon as you hovered over any of the menu tabs. I eventually worked out that if you have upgraded to ASP.NET 4.0 (as I have) then the menu will not work unless you have the following entry in web.config.

  30. David Says:

    For some odd reason, the final line (the most important line!) of my last post was not accepted. Let me try again without surrounding the text with GT and LT characters.

    You need the following entry in the pages statement within web.config,

    controlRenderingCompatibilityVersion = “3.5”

  31. Great post. There’s a lot of useful info. I did want to let you know something though – I am running Debian with the up-to-date of Firefox and the design of your blog is kind of flaky for me. I can enjoy the articles, but the navigation doesn’t function so good.

Comments are closed.

%d bloggers like this: