---
title: Creating a navigation menu
---

> 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).

> **Info:** This page is a part of a tutorial, which you should follow sequentially from beginning to end. [Go to the first page: Using the Xperience interface](https://docs.kentico.com/13tutorial/using-the-xperience-interface.md).

In the [previous step](https://docs.kentico.com/13tutorial/developer-tutorial/asp-net-core-development-tutorial/displaying-page-content.md) of this tutorial, you have implemented the functionality that retrieves page data from the database and displays it on the live site. In this step, you will code a dynamic menu that allows your content editors to manage the website's navigation.

Website navigation tends to change based on the site's current content and the requirements of its owner. The _Navigation item_ feature of page types allows content editors to set the **Show in menu** flag for individual pages, and thus control which pages from the content tree appear in the navigation menu.

On the side of the live site application's code, you need to retrieve page data based on the _Show in menu_ flag, and then handle the menu's presentation, design, and behavior. This dynamic approach gives editors full control over the navigation menu items, without the need to adjust and redeploy the site's code.

## You will learn about:

## Creating a view model for the menu items

1. In Visual Studio, create a new **Menu** subfolder in the **Models** folder.
2. Select the _Menu_ subfolder and add a new **MenuItemViewModel** class.
3. Define the view model properties using the following code:

   ```csharp

   namespace MEDIOClinic.Models
   {
       public class MenuItemViewModel
       {
           // Defines the properties of the MenuItem view model
           public string MenuItemText { get; set; }
           public string MenuItemRelativeUrl { get; set; }         
       }
   }

   ```
4. Save your changes.

## Creating a view component for the navigation menu

We'll add the site's navigation menu using an ASP.NET Core's [view components](https://learn.microsoft.com/en-us/aspnet/core/mvc/views/view-components). The view component's _InvokeAsync_ method loads and displays the content of the site's navigation menu. The method retrieves the menu data and organizes it into a collection of _MenuItemViewModels_ that gets passed to the component's view.

1. Create a new **ViewComponents** folder in your Core project.
2. Add a new **NavigationMenuViewComponent** class to the folder.
3. Replace the default code of the class with the following:

   ```csharp

   using System.Threading.Tasks;
   using System.Collections.Generic;
   using System.Linq;

   using Microsoft.AspNetCore.Mvc;

   using CMS.Core;
   using CMS.DocumentEngine;
   using CMS.DocumentEngine.Routing;

   using Kentico.Content.Web.Mvc;

   using MEDIOClinic.Models;

   namespace CoreTutorial.ViewComponents
   {   
       public class NavigationMenuViewComponent : ViewComponent
       {
           private readonly IPageRetriever pageRetriever;
           private readonly IPageUrlRetriever pageUrlRetriever;

           public NavigationMenuViewComponent(IPageRetriever pageRetriever, IPageUrlRetriever pageUrlRetriever)
           {
               // Initializes instances of required services using dependency injection
               this.pageRetriever = pageRetriever;
               this.pageUrlRetriever = pageUrlRetriever;
           }

           public async Task<IViewComponentResult> InvokeAsync()
           {
               // Retrieves a collection of page objects with data for the menu (pages of all page types)
               IEnumerable<TreeNode> menuItems = await pageRetriever.RetrieveAsync<TreeNode>(query => query
                                                       // Selects pages that have the 'Show in menu" flag enabled
                                                       .MenuItems()
                                                       // Only loads pages from the first level of the site's content tree
                                                       .NestingLevel(1)
                                                       // Filters the query to only retrieve required columns
                                                       .Columns("DocumentName", "NodeID", "NodeSiteID")
                                                       // Loads pages together with their URL path data (performance reasons)
                                                       .WithPageUrlPaths()
                                                       // Uses the menu item order from the content tree
                                                       .OrderByAscending("NodeOrder"));

               // Creates a collection of view models based on the menu item data
               IEnumerable<MenuItemViewModel> model = menuItems.Select(item => new MenuItemViewModel()
               {
                   // Gets the name of the page as the menu item caption text
                   MenuItemText = item.DocumentName,
                   // Retrieves the URL for the page (as a relative virtual path)
                   MenuItemRelativeUrl = pageUrlRetriever.Retrieve(item).RelativePath
               });

               return View(model);
           }
       }
   }

   ```
4. Save your changes.

> **Info:** The code retrieves page data for all page types using the Xperience **DocumentQuery** API. DocumentQuery provides an abstraction layer over your SQL database and allows you to call additional methods that adjust how the page data is retrieved.
>
> For example, the _OrderByAscending_ method sets the order of the retrieved data items, and the _Columns_ method ensures that the underlying SQL query only loads the data columns that you need. For performance reasons, we strongly recommend limiting columns in all data retrieval API calls.
>
> See the documentation if you wish to learn more: [Working with pages in the API](https://docs.kentico.com/13/custom-development/working-with-pages-in-the-api.md)

## Creating the navigation menu view

A navigation menu is an element that appears on most pages of a website. We'll define the menu's output in a partial view that is returned by our view component. The menu can then be added to the site's main layout (and reused on other pages if necessary).

1. In Visual Studio under **\~/Views/Shared**, create a new **Components** folder.
2. Within the _Components_ folder, create a new **NavigationMenu** folder.
3. Inside the _NavigationMenu_ folder, create a new view called **Default.cshtml.**
4. Replace the default code of the view with:

   ```csharp

   @using MEDIOClinic.Models;

   @model IEnumerable<MenuItemViewModel>

   <nav>
       @foreach (MenuItemViewModel menuItem in Model)
       {
           @* Iterates through the view model collection and renders HTML links for the menu items *@
           <a href="@menuItem.MenuItemRelativeUrl" title="@menuItem.MenuItemText">@menuItem.MenuItemText</a>
       }
   </nav>

   ```
5. Save your changes.

## Updating the website layout

You have coded the functionality behind the navigation menu. Let's put the code to use and add the menu to the site's layout.

1. Edit your _\_Layout.cshtml_ file (in the _Views/Shared_ folder).
2. Locate the section defined by __ tags, and replace it with a **Component.InvokeAsync("NavigationMenu")** call. This renders our _NavigationMenuViewComponent_ using the _Default.cshtml_ view we created. Since this is an asynchronous operation, don't forget to include the _await_ directive!
3. Locate the __ element in the __ section that displays the _MEDIO clinic_ logo, and set the value of the _href_ attribute to: \~/home

Your final _\_Layout.cshtml_ markup should look like this:

```xml

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    @* Dynamically resolves the page's title *@
    <title>Medio Clinic - @ViewBag.Title</title>
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.6.3/css/font-awesome.min.css">
    <link href="https://fonts.googleapis.com/css?family=Lato:400,700italic&subset=latin,latin-ext" rel="stylesheet" type="text/css">
    <link href="https://fonts.googleapis.com/css?family=Lobster" rel="stylesheet" type="text/css">
    <link href="~/css/styles.css" rel="stylesheet" type="text/css" />
    @* Razor section for additional page-specific styles *@
    @RenderSection("styles", required: false)
</head>
<body>
    <header>
        <div class="col-sm-offset-3 col-sm-6">
            <div class="col-sm-6">
                @* Targets the root page of the website *@
                <a href="~/home" title="MedioClinic homepage" class="logo">MEDIO clinic</a>
            </div>
            <div class="col-sm-6 nav">
                @* Renders the view component with the navigation menu, including the <nav> element *@
                @await Component.InvokeAsync("NavigationMenu")
            </div>
        </div>
        <div class="clearfix"></div>
    </header>
    @* Loads the content of your Tutorial's pages as sub views *@
    @RenderBody()
    <footer>
        <div class="col-sm-offset-3 col-sm-6">
            <div class="row">
                <div class="col-sm-6">
                    <h4>MEDIO clinic</h4>
                    <ul>
                        <li><i class="fa fa-map-marker"></i> Address: <address>7A Kentico street, Bedford, NH 03110, USA</address></li>
                        <li><i class="fa fa-envelope-o"></i> E-mail: <a href="mailto:info@medio-clinic.com" title="Email us">info@medio-clinic.com</a></li>
                        <li><i class="fa fa-phone"></i> Phone number: <a href="tel:5417543010" title="Phone us">(541) 754-3010</a>
                    </ul>
                </div>
                <div class="col-sm-6">
                    <span class="cms">Powered by <a href="https://xperience.io/" title="Kentico Xperience CMS">Kentico Xperience CMS for ASP.NET Core</a></span>
                </div>
            </div>
        </div>
        <div class="clearfix"></div>
    </footer>
    @* Razor section for additional page-specific scripts *@
    @RenderSection("scripts", required: false)
</body>
</html>

```

Build your project and test your navigation menu on the live site website. Because the original layout already contained hard-coded HTML links, you won't see a difference on the live site. However, you can test the menu's dynamic functionality by adding another page in the Xperience administration interface (_Pages_ application), or by changing the order of the _Home_ and _Medical center_ items. The implementation you've built ensures any menu item changes are immediately displayed in the navigation menu.

You can download packages with the [exported MEDIO clinic website](https://docs.kentico.com/docsassets/13tutorial/creating-a-navigation-menu/Xperience13_CoreTutorial_ExportedWebsite.zip) and the [MEDIOClinic project files](https://docs.kentico.com/docsassets/13tutorial/creating-a-navigation-menu/Xperience13_CoreTutorial_ProjectFiles.zip). To compare the sample solution with your own implementation, import the website into your Xperience installation in the **Sites** application or view the code of the MVC application in Visual Studio.

**Previous page:** [Displaying page content](https://docs.kentico.com/13tutorial/developer-tutorial/asp-net-core-development-tutorial/displaying-page-content.md) — **Next page:** [Next steps in Xperience development](https://docs.kentico.com/13tutorial/developer-tutorial/asp-net-core-development-tutorial/next-steps-in-xperience-development.md)

**Completed pages:** 9 of 10
