How to Create a Custom Modal Component in Blazor

Custom Modal Component in Blazor with Animation

Are you still using JavaScript modals in your Blazor app? It’s time to level up. Building custom modal components in Blazor not only keeps your app more C#-centric but also makes it easier to manage UI state and enhance reusability.

Understanding the Role of Modals in Web Apps

What is a Modal?

A modal is a UI overlay that captures user attention by presenting information or requiring input without leaving the current page. They’re commonly used for:

  • Alert dialogs
  • Confirmations
  • Forms (e.g., login, signup)

In terms of UX, modals help streamline workflows by keeping users in context.

Why Use Modals in Blazor?

Blazor’s component model is perfect for crafting modals:

  • Encapsulation: Modal behavior and styles can be neatly contained.
  • Reusability: Easily reuse modals across multiple pages.
  • C# integration: You can manage modal state and interactions purely with .NET.

Setting Up Your Blazor Project for Modal Components

Prerequisites and Tools

To follow this guide, ensure you have:

  • .NET 8 SDK
  • Visual Studio 2022+ or VS Code
  • A Blazor WebAssembly or Server App

Structuring Your Project for Reusability

A good starting point:

  • /Components/Modal — All modal-related files
  • /wwwroot/css/modal.css — Styles for modal animation and layout

Keep markup, logic, and styles modular and tidy.

Building the Basic Modal Component

Creating the Modal Markup and Styles

Create Modal.razor:

<div class="modal-overlay" @onclick="Close">
    <div class="modal-container" @onclick:stopPropagation>
        @ChildContent
    </div>
</div>

Add styles in modal.css:

.modal-overlay {
    position: fixed;
    top: 0; left: 0; right: 0; bottom: 0;
    background-color: rgba(0,0,0,0.5);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 1000;
}
.modal-container {
    background: white;
    padding: 1.5rem;
    border-radius: 10px;
    min-width: 300px;
}

Handling Visibility and State

Update Modal.razor.cs:

[Parameter] public bool IsVisible { get; set; }
[Parameter] public EventCallback OnClose { get; set; }

private async Task Close()
{
    if (OnClose.HasDelegate)
        await OnClose.InvokeAsync();
}

Conditionally render in Modal.razor:

@if (IsVisible)
{
    <div class="modal-overlay" @onclick="Close">
        <div class="modal-container" @onclick:stopPropagation>
            @ChildContent
        </div>
    </div>
}

Adding Slot-like Content Support

Add:

[Parameter] public RenderFragment? ChildContent { get; set; }

This allows flexible insertion of any content into the modal.

Enhancing the Modal with Animations

Using CSS Transitions for Smooth Effects

Update modal.css:

.modal-container {
    opacity: 0;
    transform: scale(0.9);
    transition: all 0.3s ease;
}
.modal-overlay.show .modal-container {
    opacity: 1;
    transform: scale(1);
}

Use a @ref to toggle the show class after render.

Integrating with Blazor Lifecycle Events

In OnAfterRenderAsync, apply CSS class:

protected override async Task OnAfterRenderAsync(bool firstRender)
{
    if (firstRender && IsVisible)
    {
        await JS.InvokeVoidAsync("setTimeout", 0); // trigger class change
    }
}

Making the Modal Truly Reusable

Parameterizing Modal Behavior

Add parameters:

[Parameter] public string Title { get; set; } = "";
[Parameter] public string Theme { get; set; } = "light";

Render them dynamically in the markup.

Creating an EventCallback API

Expose user interactions:

[Parameter] public EventCallback OnConfirm { get; set; }
[Parameter] public EventCallback OnCancel { get; set; }

Common Modal Use Cases in Blazor

Form Inside a Modal

Embed a EditForm for login/signup. Example:

<EditForm Model="loginModel" OnValidSubmit="HandleLogin">
    <InputText @bind-Value="loginModel.Username" />
    <InputText @bind-Value="loginModel.Password" type="password" />
    <button type="submit">Login</button>
</EditForm>

Alert and Confirmation Dialogs

Add ModalConfirm.razor:

<Modal IsVisible="@IsOpen" OnClose="Hide">
    <h3>Are you sure?</h3>
    <button @onclick="Confirm">Yes</button>
    <button @onclick="Hide">Cancel</button>
</Modal>

Advanced Tips and Best Practices

Accessibility and Keyboard Support

To make your modals accessible:

  • Add role="dialog" and aria-modal="true" to the modal container.
  • Use tabindex="-1" to allow focus on the modal.
  • Set initial focus to the modal when it opens. You can do this in OnAfterRenderAsync using JavaScript interop:
// JS function
function focusModal() {
    document.querySelector('.modal-container')?.focus();
}
await JS.InvokeVoidAsync("focusModal");
  • Handle Escape key to close the modal:
@onkeydown="HandleKeyDown"
private void HandleKeyDown(KeyboardEventArgs e)
{
    if (e.Key == "Escape") Close();
}

Lazy Loading and Performance Optimization

Heavy content inside modals (like charts or long forms) can slow down page loads. Optimize by rendering conditionally:

@if (IsVisible)
{
    <MyHeavyComponent />
}

This ensures the modal content isn’t loaded until actually visible, improving startup performance and responsiveness.

FAQ: Your Questions About Blazor Modals

Can I show multiple modals at once?

Technically yes, but UX-wise it’s not recommended. Manage modal stack manually if needed.

How to close the modal with Escape key?

Add a KeyboardListener JS interop or use onkeydown and handle key event in Blazor.

Is this approach Server-side friendly?

Absolutely. Works in both Blazor Server and WASM.

Conclusion: Create Better UX with Reusable Blazor Modals

If you’re tired of clunky modal logic, this guide gives you a solid base to build flexible, animated, and fully .NET-integrated modal components. Implement it once and reuse it across your app with zero JavaScript.

Let me know how you use modals in your app — do you use custom components or 3rd-party libraries?

Leave a Reply

Your email address will not be published. Required fields are marked *