ASP.NET

How to use the ASP.NET Menu control: static items, Web.sitemap and styling

ASP.NET · · Published 2026-10-14

The Menu control renders a navigation menu with optional fly-out sub-menus. You can type the items into the markup, or point the menu at a Web.sitemap file so the same structure drives the menu, breadcrumbs and access rules. Since .NET 4 it renders clean nested lists that you style with your own CSS.

A menu with static items

<asp:Menu ID="mnuMain" runat="server" Orientation="Horizontal"
    StaticDisplayLevels="1" MaximumDynamicDisplayLevels="2" CssClass="main-menu">
    <Items>
        <asp:MenuItem Text="Home" NavigateUrl="~/Default.aspx" />
        <asp:MenuItem Text="Products" NavigateUrl="~/Products/Default.aspx">
            <asp:MenuItem Text="Software" NavigateUrl="~/Products/Software.aspx" />
            <asp:MenuItem Text="Training" NavigateUrl="~/Products/Training.aspx" />
        </asp:MenuItem>
        <asp:MenuItem Text="Contact" NavigateUrl="~/Contact.aspx" />
    </Items>
</asp:Menu>

An item without NavigateUrl causes a postback when clicked and raises MenuItemClick, which you can handle on the server. For navigation, links are better: they work without JavaScript and can be opened in a new tab.

Driving the menu from Web.sitemap

A site map is an XML file at the application root that describes the site's hierarchy:

<?xml version="1.0" encoding="utf-8" ?>
<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0">
  <siteMapNode url="~/Default.aspx" title="Home" description="Start page">
    <siteMapNode url="~/Products/Default.aspx" title="Products" description="All products">
      <siteMapNode url="~/Products/Software.aspx" title="Software" description="" />
      <siteMapNode url="~/Products/Training.aspx" title="Training" description="" />
    </siteMapNode>
    <siteMapNode url="~/Contact.aspx" title="Contact" description="How to reach us" />
    <siteMapNode url="~/Admin/Default.aspx" title="Administration" description="" roles="Admins" />
  </siteMapNode>
</siteMap>

Each URL may appear only once in the file. Bind the menu through a SiteMapDataSource:

<asp:SiteMapDataSource ID="smds" runat="server" ShowStartingNode="false" />
<asp:Menu ID="mnuMain" runat="server" DataSourceID="smds" Orientation="Horizontal"
    StaticDisplayLevels="1" CssClass="main-menu" />

ShowStartingNode="false" hides the root ("Home") node so its children become the top level; add a separate Home link if you want one. The node's description becomes the item's tooltip.

The same Web.sitemap feeds a SiteMapPath breadcrumb, described in the breadcrumb example.

Hiding items by role

The roles attribute above only takes effect with security trimming enabled:

<system.web>
  <siteMap defaultProvider="XmlSiteMapProvider" enabled="true">
    <providers>
      <clear />
      <add name="XmlSiteMapProvider" type="System.Web.XmlSiteMapProvider"
           siteMapFile="Web.sitemap" securityTrimmingEnabled="true" />
    </providers>
  </siteMap>
</system.web>

With trimming on, a node is shown only if the user is authorised for its URL (by the <authorization> rules) or belongs to a role listed in roles. Hiding a menu item is not access control: protect ~/Admin with <authorization> rules in web.config as well.

Rendering and styling

Since .NET 4, RenderingMode="List" (the default for applications targeting 4.0 or later) outputs nested <ul>/<li>/<a> elements; earlier versions produced nested tables. The old style properties (StaticMenuItemStyle and friends) become inline styles, so it is cleaner to style through your own class:

.main-menu ul { list-style: none; margin: 0; padding: 0; }
.main-menu a { display: block; padding: .5rem .9rem; color: #1b2a3a; text-decoration: none; }
.main-menu a:hover, .main-menu a:focus { background: #e8eef5; }
.main-menu a.selected { font-weight: 700; border-bottom: 2px solid #1b6aa5; }

/* fly-out level */
.main-menu ul.level2 { background: #fff; border: 1px solid #ccd6e0; min-width: 12rem; }

The control adds classes such as level1, level2, static, dynamic and selected to the generated elements. Inspect the output in the browser's developer tools to see exactly what your version emits. The fly-out behaviour itself is implemented by a script the control registers, which also sets some inline positioning styles; set IncludeStyleBlock="false" to stop it from adding its default style block and keep full control.

Highlighting the current page

When bound to a site map, the menu marks the item for the current URL as selected automatically. With static items, select it yourself, for example in a master page:

protected void Page_Load(object sender, EventArgs e)
{
    string current = Request.AppRelativeCurrentExecutionFilePath; // e.g. "~/Contact.aspx"
    foreach (MenuItem item in mnuMain.Items)
    {
        if (string.Equals(item.NavigateUrl, current, StringComparison.OrdinalIgnoreCase))
        {
            item.Selected = true;
            break;
        }
    }
}

Handling clicks on the server

<asp:Menu ID="mnuTabs" runat="server" Orientation="Horizontal" OnMenuItemClick="mnuTabs_MenuItemClick">
    <Items>
        <asp:MenuItem Text="Details" Value="0" Selected="true" />
        <asp:MenuItem Text="History" Value="1" />
    </Items>
</asp:Menu>
<asp:MultiView ID="mvTabs" runat="server" ActiveViewIndex="0">
    <asp:View runat="server">Details...</asp:View>
    <asp:View runat="server">History...</asp:View>
</asp:MultiView>
protected void mnuTabs_MenuItemClick(object sender, MenuEventArgs e)
{
    mvTabs.ActiveViewIndex = int.Parse(e.Item.Value);
}

This classic tab pattern uses postbacks; each click reloads the page.

Accessibility and mobile

Troubleshooting

Official documentation