Search code examples
c#asp.net-coreblazorblazor-server-side

How to make a dropdown menu in Blazor


I am trying to make a simple dropdown menu in my Blazor app. It is declared in my Header.razor as shown below:

    <div class="header-sign">
        <div class="dropdown" id="toggleDropdown">
            <button class="button-md" type="button">
                <i data-feather="user"></i>
                <span>Personal cab</span>
            </button>
            <ul class="dropdown-list">
                <li class="dropdown-item">
                    <a class="dropdown-link" href="">
                        <p class="text-md">Cabinet</p>
                    </a>
                </li>
                <li class="dropdown-item">
                    <a class="dropdown-link" href="">
                        <p class="text-md">Sign out</p>
                    </a>
                </li>
            </ul>
        </div>
    </div>

The dropdown can be triggered via JS script like this:

$("#toggleDropdown").on("mouseenter", () => {
$(this).find(".dropdown-list").addClass("is-active");
});

I have my header declared in MainLayout.razor like shown below:

@inherits LayoutComponentBase

<Header></Header>

<main class="main">
    @Body
</main>

<Footer></Footer>

And this approach doesn't work.

Everything changes if I replace the above-mentioned Header.razor with razor page Header.cshtml with exactly the same markup and render it in _Layout.cshtml in such a way:

@await Html.PartialAsync("Header")

Looks like the above markup can only work in *.cshtml files but cannot in *.razor and I don't quiet understand the reason. Why does it behave this way?


Solution

  • Huge thanks to Mohammed Alwedaei, I figured out how to solve my question. His remark that the dropdown should be activated on a click and not on a hover really solved it to me.

    We should just keep state of a dropdown list and toggle classes of it in a bit tricky way (with a ternary operator @(isActive ? "is-active" : "")). To make the dropdown work as intended, we should define @onclick attribute and also @onblur to disable it when user clicks somewhere else.

    The code below works just fine:

    <div class="header-sign">
        <div class="dropdown" id="toggleDropdown">
            <button @onclick="Show" @onblur="Hide" class="button-md" type="button">
                <i data-feather="user"></i>
                <span>Personal cab</span>
            </button>
            <ul class="dropdown-list @(isActive ? "is-active" : "")">
                <li class="dropdown-item">
                    <a class="dropdown-link" href="/cabinet">
                        <p class="text-md">Cabinet</p>
                    </a>
                </li>
                <li class="dropdown-item">
                    <a @onclick="LogOutAsync" class="dropdown-link" href="">
                        <p class="text-md">LogOut</p>
                    </a>
                </li>
            </ul>
        </div>
    </div>
    
    @code {
        private bool isActive = false;
    
        private void Show()
        {
            isActive = true;
        }
    
        private void Hide()
        {
            isActive = false;
        }
    
        private async Task LogOutAsync()
        {
            
        }
    }