blazor-menus-links-navlink

Blazor Menus & Links with NavLink

  • 3 min

A NavLink is a link component that adds a CSS class when its destination matches the current URL.

For navigation, you can use a standard <a> tag:

<a href="/home">Inicio</a>
Copied!

The link works, but it does not indicate by itself whether its destination is the current location.

NavLink resolves this active state without requiring us to manually compare the URL.

NavLink is a component that wraps the standard <a> tag. In fact, when Blazor renders the page, you will see an <a> in the final HTML.

However, NavLink has internal logic that constantly monitors the browser’s URL. If the current URL matches the link’s href, NavLink automatically adds a CSS class to the element (by default, the active class).

Basic usage

<nav>
    <NavLink class="nav-link" href="/">
        🏠 Home
    </NavLink>

    <NavLink class="nav-link" href="/counter">
        ➕ Counter
    </NavLink>
</nav>
Copied!

Thanks to this, you can write a very simple CSS rule to highlight the current section:

/* In your CSS file */
.nav-link.active {
    background-color: rgba(255, 255, 255, 0.1);
    font-weight: bold;
    color: white;
}
Copied!

Match strategies with Match

Suppose you are at /products/details.

  • Your link to “Products” (href="/products") should be active.
  • But, should your link to “Home” (href="/") be active?

Technically, /products/details starts with /. If Blazor used a simple match, the “Home” link would always be highlighted, because all routes start with the root.

To control this, NavLink has the Match property.

This is the default option. The link is activated if the current URL starts with the href value.

It is ideal for groupings or dropdown menus.

  • Link: <NavLink href="/admin">
  • Current URL: /admin/users/create
  • Result: ACTIVE (because it starts with /admin).

This option forces an exact match. The URL must be identical to the href.

It is the usual option for the home link, because it prevents the root from appearing selected when visiting other routes. In .NET 10, the All comparison ignores query strings and fragments by default if the path matches.

<NavLink class="nav-link" href="" Match="NavLinkMatch.All">
    Home
</NavLink>

<NavLink class="nav-link" href="products">
    Products
</NavLink>
Copied!

Mnemonic rule: Does the link point to the root (/)? Use Match="NavLinkMatch.All". Does it point anywhere else? The default (Prefix) will likely suffice.

Customizing the active class

By default, Blazor adds the active class. This is great because frameworks like Bootstrap already have styles defined for that class.

If you use a different CSS library, like Tailwind or Bulma, you might need a different class, for example is-selected or bg-blue-500. You can customize it too.

We have two options:

1. Globally (for the entire NavLink): Using the ActiveClass parameter.

<NavLink class="boton-menu" ActiveClass="is-selected" href="/profile">
    My Profile
</NavLink>
Copied!

2. Inheriting and creating your own component: If you don’t want to write ActiveClass="..." fifty times, create your own component MyLink.razor that inherits from NavLink and changes the default value.

Side menu example

Let’s see how a typical navigation menu looks (like the one generated by the Visual Studio template in NavMenu.razor).

<div class="top-row ps-3 navbar navbar-dark">
    <div class="container-fluid">
        <a class="navbar-brand" href="">My Blazor App</a>
    </div>
</div>

<div class="nav-scrollable">
    <nav class="flex-column">

        <div class="nav-item px-3">
            <NavLink class="nav-link" href="" Match="NavLinkMatch.All">
                <span class="bi bi-house-door-fill"></span> Home
            </NavLink>
        </div>

        <div class="nav-item px-3">
            <NavLink class="nav-link" href="counter">
                <span class="bi bi-plus-square-fill"></span> Counter
            </NavLink>
        </div>

        <div class="nav-item px-3">
            <NavLink class="nav-link" href="fetchdata">
                <span class="bi bi-list-nested"></span> Fetch data
            </NavLink>
        </div>

    </nav>
</div>
Copied!

Of course, the href attribute of a NavLink accepts C# expressions, just as we saw with One-Way Binding.

@foreach (var categoria in Categorias)
{
    <NavLink class="nav-link" href="@($"catalog/{categoria.Slug}")">
        @categoria.Nombre
    </NavLink>
}
Copied!