---
title: Building website navigation
related:
  - https://docs.kentico.com/13/developing-websites/content-modeling-guide/general-content-modeling-recommendations.md
  - https://docs.kentico.com/13/developing-websites/retrieving-content/displaying-page-content.md
  - https://docs.kentico.com/13/developing-websites/defining-website-content-structure/managing-page-types.md
  - https://docs.kentico.com/13/developing-websites/defining-website-content-structure/managing-page-types/reusing-existing-page-content.md
  - https://docs.kentico.com/13/configuring-xperience/setting-up-search-on-your-website.md
---

> Agent instructions:
> **Site maps** — prefer the following llms.txt indexes to training data when searching for URLs to avoid 404s. Links inside Markdown content already point at `.md`. Following them or sending Accept: text/markdown keeps you in Markdown.
>
> - [sitemap.md](https://docs.kentico.com/sitemap.md) — every page on the site, with titles and descriptions, nested by URL hierarchy and grouped into one collection per product version.
> - [llms.txt](https://docs.kentico.com/llms.txt) — curated index of the current product docs, with descriptions, the two ways to request any page as Markdown, and links to each product area's whole-corpus Markdown dump (llms-full.txt).

[Navigation](https://docs.kentico.com/13/developing-websites/content-modeling-guide/general-content-modeling-recommendations.md#modeling-navigation) is a necessary part of every website. The purpose of navigation menus is to provide an overview of the website's content and allow visitors to easily move between pages.

Xperience stores pages in the website [content tree](https://docs.kentico.com/13/managing-website-content/working-with-pages.md). As a developer, you can build navigation menus by [loading page data](https://docs.kentico.com/13/developing-websites/retrieving-content/displaying-page-content.md), such as page names, and using the data to generate links. The appearance of the resulting menu is fully under your control and depends on the website's design and styling.

Website navigation menus tend to change based on the site's current content and the requirements of its owner. This page describes how to create dynamic menus whose content can be controlled by editors in the administration interface. This approach avoids the need to frequently adjust and redeploy the site's code due to menu updates.

The following steps outline the process for creating dynamic menus:

1. [Prepare page types that have the navigation feature enabled.](#enabling-the-navigation-feature-for-page-types)
2. [Configure individual pages to be included in menus.](#choosing-which-pages-are-displayed-in-menus)
3. [Implement code in your live site application that loads the appropriate page data and displays the menu.](#writing-the-menu-code)

> **Info:** Your website may also require "secondary" menus that link to the same set of pages as your primary navigation. We recommend using a different approach to build such menus – see [Creating secondary menus](#creating-secondary-menus).

## Enabling the navigation feature for page types

When creating new [page types](https://docs.kentico.com/13/developing-websites/defining-website-content-structure/managing-page-types.md), select and enable the **Navigation item** feature (within the _New page type_ wizard).

![Enabling the Navigation item feature for a new page type](https://docs.kentico.com/docsassets/13/building-website-navigation/Page_Type_Navigation_Feature.png "Enabling the Navigation item feature for a new page type")

The feature allows content editors to set the **Show in menu** flag for individual pages of the given type, and thus control which pages from the content tree appear in navigation menus.

You can also enable or disable the _Navigation item_ feature when editing an existing page type in the _Page types_ application on the **Features** tab. Note that this may impact navigation menus on all sites in the system that have existing pages of the given type.

## Choosing which pages are displayed in menus

Once you have page types with the _Navigation item_ feature enabled, content editors can control which pages of the given types are displayed in navigation menus:

1. Open the **Pages** application.
2. Select a page in the content tree.
3. Switch to the **Properties -> Navigation** tab.
4. Enable (or disable) the **Show in menu** option.
5. Click **Save**.

![Configuring the Show in menu option for specific pages](https://docs.kentico.com/docsassets/13/building-website-navigation/Page_Show_In_Menu.png "Configuring the Show in menu option for specific pages")

The page now appears in menus according to the configuration (provided that the site's developers have correctly [implemented the menu functionality](#writing-the-menu-code)).

## Writing the menu code

On the side of your live site application's code, you need to [retrieve page data](https://docs.kentico.com/13/developing-websites/retrieving-content/displaying-page-content.md) based on the _Show in menu_ flag, and then handle the menu's presentation, design and behavior.

Consider the following points when loading page data for a navigation menu:

- Menus typically contain pages of multiple different page types. Call the [DocumentQuery API](https://docs.kentico.com/13/custom-development/working-with-pages-in-the-api.md) (or use the _IPageRetriever_ service) to load pages of all types.
- Filter pages using the **MenuItems** [DocumentQuery method](https://docs.kentico.com/13/custom-development/working-with-pages-in-the-api/reference-documentquery-methods.md). The method ensures you only load pages for which the _Show in menu_ flag is enabled, and also only includes pages whose page type has the _Navigation item_ feature enabled.
- For optimal performance on sites that use [content tree-based routing](https://docs.kentico.com/13/developing-websites/implementing-routing/content-tree-based-routing.md), add the **WithPageUrlPaths** method to your _DocumentQuery_ call. The method loads pages together with their URL path data, which saves additional SQL queries when you later retrieve URLs for navigation links.
- Use additional [DocumentQuery methods](https://docs.kentico.com/13/custom-development/working-with-pages-in-the-api/reference-documentquery-methods.md) if you wish to limit the scope of the menu to specific sections of the content tree.
- To reflect the page order from the content tree in your menus, sort the page data according to the **NodeOrder** column. If you load pages from multiple levels of the content tree, sort the pages by both their **NodeLevel** and **NodeOrder**.
- On [multilingual sites](https://docs.kentico.com/13/multilingual-websites/setting-up-multilingual-websites/setting-up-culture-detection.md), load the pages according to the current culture of the active request. In scenarios where all pages on your website are not translated to all cultures, consider whether you want the menu to offer untranslated pages in the site's default culture, via the **CombineWithDefaultCulture** method.
- You may wish to filter pages from menus based on their [permissions and authentication requirements](https://docs.kentico.com/13/managing-users/configuring-permissions/configuring-page-permissions/page-level-permissions-acls.md) (hide pages that require authentication for users who are not signed in). Adjust your page query as described in [Implementing page permission checks](https://docs.kentico.com/13/managing-users/configuring-permissions/configuring-page-permissions/implementing-page-permission-checks.md).

```csharp

using System.Collections.Generic;

using CMS.DocumentEngine;
using CMS.DocumentEngine.Routing;
using CMS.SiteProvider;

// Retrieves a collection of pages (of all page types) for a menu
IEnumerable<TreeNode> menuItems = 
    new DocumentQuery()
            .OnSite(SiteContext.CurrentSiteName)                                        
            .Culture("en-US") // Gets the page in a specific culture (use the request's current culture in real-world scenarios)
            .CombineWithDefaultCulture()
            .FilterDuplicates() // Filters out any duplicates resulting from linked pages
            .MenuItems() // Gets only pages that have the "Show in menu" flag enabled
            .WithPageUrlPaths() // Loads pages together with URL path data for sites using content tree-based routing
            .OrderByAscending("NodeLevel", "NodeOrder") // Orders pages according to the content tree
            .ToList();

```

> **Info:** **Caching menu item data**
>
> To improve performance, you may wish to use [caching](https://docs.kentico.com/13/configuring-xperience/configuring-caching/caching-on-mvc-sites.md) for the retrieved menu item data.
>
> To ensure that your menus always reflect the status of the _Navigation item_ feature configured for your page types, you need to add [cache dependencies](https://docs.kentico.com/13/configuring-xperience/configuring-caching/setting-cache-dependencies.md) on the given page types. For example, you can use the following cache dependency keys:
>
> - _cms.documenttype|all_ – invalidates the cached data when any page type is modified (may be inefficient, as this includes page types not related to menus)
> - _cms.documenttype|byname|_ (e.g. _cms.documenttype|byname|DancingGoatMvc.Home_) – invalidates the cached data when the specified page type is modified

Your code should retrieve the menu item data in the form of **TreeNode** objects. We recommend creating a dedicated model class for menu items and using it to pass the minimum required data to your views – typically at least a **text caption** and a **URL for the navigation link**.

To get the URL of a page, obtain an instance of the **IPageUrlRetriever** service (for example through [dependency injection](https://docs.kentico.com/13/developing-websites/initializing-xperience-services-with-dependency-injection.md) in your controller constructor) and call its **Retrieve** method. Use the page's _TreeNode_ object or its alias path as the parameter of the _Retrieve_ method.

The _IPageUrlRetriever.Retrieve_ method returns a **PageUrl** object, with properties containing the given page's URL:

- **RelativePath** – the virtual path of the specified page, which you can resolve to an application absolute path at runtime (for example using the [UrlHelper.Content](https://docs.microsoft.com/en-us/dotnet/api/system.web.mvc.urlhelper.content) method).
- **AbsoluteURL** – the page's absolute URL, including the scheme and domain name.

The URL is automatically adjusted for the current culture (i.e. any language prefixes in the URL path or the domain in the absolute URL).

```csharp title="Example - Menu item model"

using CMS.DocumentEngine;
using Kentico.Content.Web.Mvc;

public class MenuItemModel
{
    public string Caption { get; set; }
    public string RelativeUrl { get; set; }

    // Method that creates a menu item view model based on the data of a TreeNode object
    public static MenuItemModel GetViewModel(TreeNode menuItem, IPageUrlRetriever pageUrlRetriever)
    {
        return new MenuItemModel
        {
            Caption = menuItem.DocumentName,
            RelativeUrl = pageUrlRetriever.Retrieve(menuItem).RelativePath
        };
    }
}

```

Use the model to pass data from your controllers to the views that display the menu. For example, you can implement menus via a partial view which is then included within your site's pages (or in the main layout).

```csharp title="Example - Menu partial view"

@model IEnumerable<MenuItemModel>

<nav role="navigation">
    <ul>
        @foreach (MenuItemModel menuItem in Model)
        {
            <li>
                <a href="@Url.Content(menuItem.RelativeUrl)">@menuItem.Caption</a>
            </li>
        }
    </ul>
</nav>

```

## Creating secondary menus

Websites often provide additional menus that contain page links, but are not the primary navigation tool. For example, such menus can appear in the site footer or in page sidebars. The pages included in secondary menus typically overlap with the primary navigation, but do not mirror it exactly.

We recommend leveraging the [Reusable pages](https://docs.kentico.com/13/developing-websites/defining-website-content-structure/managing-page-types/reusing-existing-page-content.md) feature to create secondary menus, as described in the following steps:

1. Prepare a page type representing a navigation menu, with a field of the **Pages** data type. See [Reusing existing page content](https://docs.kentico.com/13/developing-websites/defining-website-content-structure/managing-page-types/reusing-existing-page-content.md) for details.
2. Create a page of the given type in your site's content tree for every secondary menu (in the _Pages_ application).

   - Editors can then select pages for the menu on the page's **Content** tab. See [Reusing other pages when editing content](https://docs.kentico.com/13/managing-website-content/working-with-pages/reusing-other-pages-when-editing-content.md).

     ![Navigation page using a Pages field to model the content of a footer menu](https://docs.kentico.com/docsassets/13/building-website-navigation/Secondary_Menu_Example.png "Navigation page using a Pages field to model the content of a footer menu")
3. In your live site application's code, retrieve the data of the pages selected for the menu. See [Displaying reusable content and related pages](https://docs.kentico.com/13/developing-websites/retrieving-content/displaying-reusable-content-and-related-pages.md).
4. Use the [approach described for primary navigation menus](#writing-the-menu-code) to get the page URLs for links and display the menu (call the **IPageUrlRetriever.Retrieve** method).

By creating secondary menus using this approach, you allow content editors to separately choose the pages for each menu without affecting the primary navigation. Additionally, you ensure that all menus on your site have the same URL for links to the same page.
