Forum Discussion
Convert the standard Blazor navigation menu to a collapsible icon menu
If it helps anyone else...With Blazor Web App on NET8, you need to add the open-iconic css and add the rendermode. After making these additions, the code supplied by Gavin-Williams worked great. Thank you Gavin-Williams for putting together.
In app.css, at the top of the page add:
@import url('https://cdnjs.cloudflare.com/ajax/libs/open-iconic/1.1.1/font/css/open-iconic-bootstrap.min.css');
In app.razor make sure to add the RenderMode in both the HeadOutlet and Routes (why not?):
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <base href="/" />
    <link rel="stylesheet" href="bootstrap/bootstrap.min.css" />
    <link rel="stylesheet" href="app.css" />
    <link rel="stylesheet" href="BlazorApp1.styles.css" />
    <link rel="stylesheet" href=""
    <link rel="icon" type="image/png" href="favicon.png" />
    <HeadOutlet @rendermode="RenderMode.InteractiveServer" />
</head>
<body>
    <Routes @rendermode="RenderMode.InteractiveServer" />
    <script src="_framework/blazor.web.js"></script>
</body>
</html>jassen777 Thank you so much for this! I was tearing my hair out trying to figure out why none of my ideas for collapsing menus worked. I also added the option to have sub menu items with those icons available in the Menu Icon section. Here in my code.
@rendermode InteractiveServer
<div class="navbar-wrapper">
    <div class="top-row ps-3 navbar navbar-dark">
        <div class="container-fluid">
            <a href="/dashboard"><img src="images/NewLogo-transparent.png" alt="Brand Logo" width="30" height="30"></a>
            @if (!@IconMenuActive)
            {
                <a class="navbar-brand">Brand option</a>
            }
            <button title="Navigation menu" class="navbar-toggler" @onclick="ToggleNavMenu">
                <span class="navbar-toggler-icon"></span>
            </button>
        </div>
    </div>
    <div class="@NavMenuCssClass" @onclick="ToggleNavMenu">
        <nav class="flex-column">
            <div class="nav-item px-3" @onclick="ToggleSubMenu">
                <NavLink class="nav-link flex-container" Match="NavLinkMatch.All">
                    <span class="oi oi-dollar" aria-hidden="true" title="Home"></span>
                    @if (!@IconMenuActive)
                    {
                        <label>Accounting</label>
                        <span class="oi chevron-icon @(showSubMenu ? "oi-chevron-top" : "oi-chevron-bottom") ps-3" style="font-size: 1rem;" aria-hidden="true"></span>
                    }   
                    
                </NavLink>
                <div class="sub-menu" style="display: @(showSubMenu ? "block" : "none")">
                    <NavLink class="nav-link" href="subitem1">
                        <span class="oi oi-folder" aria-hidden="true" title="Sub Item 1"></span>
                        @if (!@IconMenuActive)
                        {
                            <label>Home</label>
                        }
                    </NavLink>
                    <NavLink class="nav-link" href="subitem2">
                        <span class="oi oi-document" aria-hidden="true" title="Sub Item 2"></span>
                        @if (!@IconMenuActive)
                        {
                            <label>Sub Menu Item 1</label>
                        }
                    </NavLink>
                </div>
            </div>
            <div class="nav-item px-3">
                <NavLink class="nav-link" href="counter">
                    <span class="oi oi-calculator" aria-hidden="true"></span>
                    @if (!@IconMenuActive)
                    {
                        <label>Sub Menu Item 2</label>
                    }   
                </NavLink>
            </div>
            <div class="nav-item px-3">
                <NavLink class="nav-link" href="fetchdata">
                    <span class="oi oi-list-rich" aria-hidden="true"></span>
                    @if (!@IconMenuActive)
                    {
                        <label>Fetch data</label>
                    }   
                </NavLink>
            </div>
        </nav>
    </div>
    <div class="bottom-row">
        <div class="icon-menu-arrow">
            @if (!@IconMenuActive)
            {
                <span class="oi oi-arrow-left" style="color: black;" @onclick="ToggleIconMenu"></span>
            }
            else
            {
                <span class="oi oi-arrow-right" style="color: black;" @onclick="ToggleIconMenu"></span>
            }
        </div>
    </div>
</div>
@code {
    private bool showSubMenu = false;
    private void ToggleSubMenu()
    {
        showSubMenu = !showSubMenu;
    }
    //bool to send to MainLayout for shrinking sidebar and showing/hide menu text
    private bool IconMenuActive { get; set; } = false;
    //EventCallback for sending bool to MainLayout
    [Parameter]
    public EventCallback<bool> ShowIconMenu { get; set; }
    private bool collapseNavMenu = true;
    private string? NavMenuCssClass => collapseNavMenu ? "collapse" : null;
    private void ToggleNavMenu()
    {
        collapseNavMenu = !collapseNavMenu;
    }
    //Method to toggle IconMenuActive bool and send bool via EventCallback
    private async Task ToggleIconMenu()
    {
        IconMenuActive = !IconMenuActive;
        await ShowIconMenu.InvokeAsync(IconMenuActive);
    }
}I'm still working on the styling but here's that as well.
.navbar-wrapper {
    border-right: 1px solid #545454;
    min-height: 100vh;
    overflow: hidden;
}
.a:hover,a:active{
    color: black;
}
.navbar-toggler {
    background-color: rgba(255, 255, 255, 0.1);
    margin-bottom: 20px;
}
.top-row {
    height: 3.5rem;
    background-color: white;
    border-bottom: 1px solid #d6d5d5;
}
    .top-row ::deep a.active, .top-row ::deep a:hover {
        color: black;
        background-color: transparent;
    }
.bottom-row {
    position: absolute;
    bottom: 3rem;
    padding-bottom: 10px;
    text-align: right;
    width: 100%;
    padding-right: 28px;
}
.icon-menu-arrow {
    text-align: right;
}
.navbar-brand {
    font-size: 1.1rem;
    color: black;
}
.oi {
    width: 2rem;
    font-size: 1.1rem;
    vertical-align: text-top;
    top: -2px;
    transition: ease-in-out 0.3s;
    transform-origin: center;
}
.chevron-icon{
    transition: transform 0.3s ease-in-out;
}
oi-chevron-top{
    transform: rotate(180deg);
}
.nav-item {
    font-size: 0.9rem;
    padding-bottom: 0.5rem;
}
    .nav-item:first-of-type {
        padding-top: 1rem;
    }
    .nav-item:last-of-type {
        padding-bottom: 1rem;
    }
    .nav-item ::deep a {
        color: #000000;
        border-radius: 4px;
        height: 3rem;
        display: flex;
        align-items: center;
        line-height: 3rem;
    }
        .nav-item ::deep a.active {
            background-color: #545454;
            color: white;
        }
        .nav-item ::deep a:hover {
            background-color: #545454;
            color: white;
        }
.sub-menu {
    display: none;
    flex-direction: column;
    padding-left: 0.5rem;
}
    .nav-item:hover .sub-menu,
    .sub-menu:hover {
        display: flex;
    }
    .sub-menu .nav-link {
        font-size: 0.8rem;
    }
@media (min-width: 641px) {
    .navbar-toggler {
        display: none;
    }
    .collapse {
        /* Never collapse the sidebar for wide screens */
        display: block;
        transition: width 1s ease;
        min-width: 300px;
    }
}
@media (max-width: 640px) {
    .bottom-row {
        display: block;
    }
}
- SCAppDevJun 18, 2024Copper ContributorMMaybe990-The submenus display (I have 3) but when I click a Menu item with sub-items, all of the sub-item are displayed. Any way to get around this? - JohnHallidaySep 20, 2025Copper ContributorI imagine you could wrap the divs within AuthorizeView Roles, like this: 
 <AuthorizeView Roles="Administrator,User">
 <Authorized>
 <div class="nav-item px-3">
 <NavLink class="nav-link" href="counter">
 <span class="bi bi-plus-square-fill-nav-menu" aria-hidden="true"></span> Counter
 </NavLink>
 </div>
 </Authorized>
 </AuthorizeView>