---
title: Implement navigation
---

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

With the navigation content types in place, let's use a view component to render the _Navigation menu_ that exists in the Content hub.

## Create view models

Start by creating view models that correspond to the _Navigation item_ and _Navigation menu_ classes.

Add a new _Navigation_ folder under _Kickstart.Web/Features_, to hold all the navigation-related files.

Inside, create the `NavigationItemViewModel`. It only needs two properties - _Title_ and _Url_.

```csharp title="NavigationItemViewModel.cs"
namespace Kickstart.Web.Features.Navigation;
public class NavigationItemViewModel
{
    public string Title { get; set; }

    public string Url { get; set; }
}
```

You might remember that in the [page template step](https://docs.kentico.com/guides/development/developer-kickstart/build-a-page-template.md#add-a-view-model-class), you defined a method that created a `LandingPageViewModel` based on a `LandingPage` object.

We need a similar method here to create a `NavigationItemViewModel` from a `NavigationItem`.

You can retrieve the page's URL simply by calling the `GetUrl` extension method of `IWebPageFieldsSource`, which every web page implements.
Return `null` if the provided item is `null` or missing its target.

```csharp title="NavigationItemViewModel.cs"
using System.Linq;
using CMS.Websites;
using Microsoft.IdentityModel.Tokens;

namespace Kickstart.Web.Features.Navigation;

public class NavigationItemViewModel
{
    public string Title { get; set; }

    public string Url { get; set; }

    // new method
    public static NavigationItemViewModel GetViewModel(NavigationItem navigationItem)
    {
        if (navigationItem?.NavigationItemTarget?.IsNullOrEmpty() ?? true)
        {
            return null;
        }

        var targetUrl = navigationItem.NavigationItemTarget.FirstOrDefault().GetUrl();

        return new NavigationItemViewModel
        {
            Title = navigationItem.NavigationItemTitle,
            Url = targetUrl.RelativePath
        };
    }
}
```

The `NavigationMenuViewModel` class also needs two properties: one to represent its _Name_ and another to represent its _Items_.

Add a static method that returns a menu view model for the provided `NavigationMenu` object, calling `NavigationItemViewModel.GetViewModel` from above for each menu item.

```csharp title="NavigationMenuViewModel.cs"
using System.Collections.Generic;
using System.Linq;

using Microsoft.IdentityModel.Tokens;

namespace Kickstart.Web.Features.Navigation;

public class NavigationMenuViewModel
{
    public string Name { get; set; }

    public IEnumerable<NavigationItemViewModel> Items { get; set; }

    public static NavigationMenuViewModel GetViewModel(NavigationMenu navigationMenu)
    {
        if (navigationMenu?.NavigationMenuItems?.IsNullOrEmpty() ?? true)
        {
            return null;
        }

        var menuItems = navigationMenu.NavigationMenuItems
            .Select(NavigationItemViewModel.GetViewModel)
            .Where(x => x != null);

        return new NavigationMenuViewModel
        {
            Name = navigationMenu.NavigationMenuDisplayName,
            Items = menuItems
        };
    }
}
```

## Define a view component

Websites often have multiple navigation menus. Let's make a view component that renders the menu. You can reuse the view component across the site.

Define an asynchronous view component with a string parameter to indicate which menu item to retrieve.

```csharp title="NavigationMenuViewComponent.cs"
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;

namespace Kickstart.Web.Features.Navigation;

public class NavigationMenuViewComponent : ViewComponent
{
    public async Task<IViewComponentResult> InvokeAsync(string navigationMenuCodeName)
    {
        // A placeholder representing the logic that retrieves the `NavigationMenu` item from the database.
        var menu = await RetrieveMenu(navigationMenuCodeName);

        if (menu == null)
        {
            return View("~/Features/Navigation/NavigationMenuViewComponent.cshtml", new NavigationMenuViewModel());
        }

        var model = NavigationMenuViewModel.GetViewModel(menu);
        
        // We will define this view in the next step.
        return View("~/Features/Navigation/NavigationMenuViewComponent.cshtml", model);
    }
}
```

> **Info:** If you copy-paste the code above, you will see a couple of issues:
>
> 1. The `RetrieveMenu` method does not exist - for now, we are using a placeholder to represent the logic that retrieves the menu item from the database.
> 2. The `~/Features/Navigation/NavigationMenuViewComponent.cshtml` view does not exist yet.
>
> We will fix both of these shortly.

Add a private method to retrieve the menu.

To query the content items, we will use the [ContentRetriever](https://docs.kentico.com/documentation/developers-and-admins/api/content-item-api/content-retriever-api.md), as we did in [the earlier step](https://docs.kentico.com/guides/development/developer-kickstart/build-a-page-template.md#query-the-landing-page). This time we'll use it's `RetrieveContent` method to get the whole menu structure, including it's items, based on a provided menu codename.

```csharp title="NavigationMenuViewComponent.cs"
using System.Linq;
using System.Threading.Tasks;
using Kentico.Content.Web.Mvc;
using Microsoft.AspNetCore.Mvc;

namespace Kickstart.Web.Features.Navigation;

public class NavigationMenuViewComponent : ViewComponent
{
    private readonly IContentRetriever contentRetriever;
    // inject the Xperience by Kentico Content retriever service
    public NavigationMenuViewComponent(IContentRetriever contentRetriever) => this.contentRetriever = contentRetriever;

    public async Task<IViewComponentResult> InvokeAsync(string navigationMenuCodeName)
    {
        var menu = await RetrieveMenu(navigationMenuCodeName);

        if (menu == null)
        {
            return View("~/Features/Navigation/NavigationMenuViewComponent.cshtml", new NavigationMenuViewModel());
        }

        var model = NavigationMenuViewModel.GetViewModel(menu);

        return View("~/Features/Navigation/NavigationMenuViewComponent.cshtml", model);
    }

    // new private method
    private async Task<NavigationMenu> RetrieveMenu(string navigationMenuCodeName)
    {
        // specify the depth of the content item tree we want to get (we need the menu and it's children items) 
        var parameters = new RetrieveContentParameters
        {
            LinkedItemsMaxLevel = 2
        };
        // retrieve the navigation menu object
        var menus = await contentRetriever.RetrieveContent<NavigationMenu>(
            parameters,
            query => query
                .Where(where => where.WhereEquals(nameof(NavigationMenu.NavigationMenuCodeName), navigationMenuCodeName)),
            RetrievalCacheSettings.CacheDisabled
            );

        return menus.FirstOrDefault();
    }
}
```

## Design the component's view

Now, we just need a view to render the model provided by `NavigationMenuViewComponent`.

Add a file called _NavigationMenuViewComponent.cshtml_ that renders a `nav` element containing a list of links from the model's `Items`.

> **Tip:** Spice up the design of the menu with some Bootstrap CSS classes.

```cshtml title="NavigationMenuViewComponent.cshtml"
@using Kickstart.Web.Features.Navigation

@model NavigationMenuViewModel

@if (Model?.Items?.Any() ?? false)
{
    <nav>
        <ul class="navbar-nav nav-underline">
            @foreach (var item in Model.Items)
            {
                <li class="nav-item">
                    <a href="@item.Url" class="nav-link link-light">@item.Title</a>
                </li>
            }
        </ul>
    </nav>
}
```

Finally, add the view component to the _\_Layout.cshtml_ view beneath the site heading, specifying _MainNavigation_ as the codename of the menu to retrieve. Adjust the Bootstrap CSS classes as necessary.

```cshtml title="_Layout.cshtml"
...
<div class="navbar navbar-primary navbar-expand-sm navbar-dark bg-primary p-3">
    <div class="navbar-brand">
        <h2>Xperience Kickstart</h2>
    </div>
    <vc:navigation-menu navigation-menu-code-name="MainNavigation" />
</div>
...
```

With all these elements in place, you should have a working navigation menu that looks something like this:

🎬 [Screen recording of working navigation](https://docs.kentico.com/docsassets/guides/implement-navigation/working-navigation.webm)

> **Tip:** If you haven't already, check out our [Kickstart repository](https://github.com/Kentico/xperience-by-kentico-kickstart) to see the complete implementation of the website we created together in this series. To run the project, follow the _README_ instructions.

Continue to the next step for additional exercises and resources.

## Continue learning

When you're ready, move on to the next page: [Next steps](https://docs.kentico.com/guides/development/developer-kickstart/next-steps.md)
