Table of Contents
Introduction
Blazor modal component is a UI that can be used to display content to users in a separate layer above the main layer, which shows the main content without requiring navigation from the current page . It can be used for forms , confirmations or some content that needs a user interaction .
In a previous post, we created a Blazor confirm dialog component that can be used in your projects. In this post, we will see how to create a Blazor Modal Component with pure C#, Html and CSS.
Take a look at the finished Blazor Modal Component implemented in a Blazor Web App.
Creating a Modal Solution and adding a Razor class library project
Open Visual Studio and create a blank solution named Modal
. Add a new Razor Class library named Dnc.Common.Razor
to the solution. Select .NET 8 (Long Term Support) as the target Framework.
Creating the DncModal component
First, create a new folder in the Dnc.Common.Razor
project named Modal. Then, create a new class file derived from the ComponentBase
class called DncModalComponent
, and add the following code.
namespace Dnc.Common.Razor.Modal
{
public class DncModalComponent<TItem> : ComponentBase
{
[Parameter] public RenderFragment<TItem> HeaderTemplate { get; set; }
[Parameter] public RenderFragment<TItem> BodyTemplate { get; set; }
[Parameter] public RenderFragment<TItem> FooterTemplate { get; set; }
[Parameter] public EventCallback<TItem> OnSubmit { get; set; }
[Parameter] public EventCallback<TItem> OnShow { get; set; }
[Parameter] public string Size { get; set; }
public EditContext EditContext { get; protected set; }
protected TItem Item { get; set; }
protected bool IsVisible { get; set; }
protected string ModalSize { get; set; } = string.Empty;
public void SetEditContext(EditContext editContext)
{
EditContext = editContext;
}
public async Task Show(TItem item = default)
{
ModalSize = Size switch
{
"Small" => "modal-sm",
"Medium" => string.Empty,
"Larg" => "modal-lg",
"ExtraLarg" => "modal-xl",
_ => string.Empty,
};
IsVisible = true;
Item = item;
var task = OnShow.InvokeAsync(Item);
if (task != null && !task.IsCompleted)
{
StateHasChanged();
await task;
}
EditContext ??= new EditContext(new { });
StateHasChanged();
}
public async Task HandleSubmit()
{
await OnSubmit.InvokeAsync(Item);
}
public void Close()
{
IsVisible = false;
Item = default;
EditContext = null;
StateHasChanged();
}
}
}
We will go over the code and provide some explanation.
[Parameter] public RenderFragment<TItem> HeaderTemplate { get; set; }
[Parameter] public RenderFragment<TItem> BodyTemplate { get; set; }
[Parameter] public RenderFragment<TItem> FooterTemplate { get; set; }
We have defined three RenderFragment<TItem>
parameter properties in the DncModalComponent
that allow us to inject the content of Blazor Modal Header, Body and Footer into the Blazor Modal component by specifying a template in the consuming Razor files for rendering each TItem
.
[Parameter] public EventCallback<TItem> OnSubmit { get; set; }
[Parameter] public EventCallback<TItem> OnShow { get; set; }
Then we declared two EventCallback<TItem>
parameters, so that the Blazor Modal component notifies consumers when the form is submitted or displayed .
The consuming component specifies which method to call when these events are triggered.
public async Task Show(TItem item = default)
{
ModalSize = Size switch
{
"Small" => "modal-sm",
"Medium" => string.Empty,
"Larg" => "modal-lg",
"ExtraLarg" => "modal-xl",
_ => string.Empty,
};
IsVisible = true;
Item = item;
var task = OnShow.InvokeAsync(Item);
if (task != null && !task.IsCompleted)
{
StateHasChanged();
await task;
}
EditContext ??= new EditContext(new { });
StateHasChanged();
}
public async Task HandleSubmit()
{
await OnSubmit.InvokeAsync(Item);
}
The Show
method sets the size of the Modal dialog depending on the Size
parameter, displays the Modal, and emits the OnShow
event when the Blazor Modal is displayed, and notifies the component to be re-rendered by calling the StateHasChanged
method, while the HandleSubmit
method emits the OnSubmit
event.
public void SetEditContext(EditContext editContext)
{
EditContext = editContext;
}
SetEditContext
is used by the consuming file to set the EditContext
property, which keeps track of the current state of the form and any validation errors raised.
The markup of the DncModal
component contains some HTML and Bootstrap CSS styles and it is self-explanatory.
In the Modal folder, create a new file called DncModal.razor
, which inherits from the DncModalComponent
class, and enter the following markup.
@inherits DncModalComponent<TItem>
@typeparam TItem
@if(IsVisible){
@if(EditContext != null){
<EditForm EditContext="@EditContext" OnSubmit="@HandleSubmit">
<div class="modal fade show dnc-modal-background" id="DncModal" style="display: block;" aria-modal="true" role="dialog">
<div class="modal-dialog @ModalSize">
<div class="modal-content">
<div class="modal-header">
@if (HeaderTemplate != null)
{
@HeaderTemplate(Item)
}
else
{
<h5 class="modal-title">Header</h5>
}
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" @onclick="Close"></button>
</div>
<div class="modal-body">
@BodyTemplate(Item)
</div>
<div class="modal-footer">
@FooterTemplate(Item)
</div>
</div>
</div>
</div>
</EditForm>
}
}
Create a new stylesheet file in the Modal folder calledDncModal.razor.css
and add the following styles.
.modal-dialog {
margin-top: 7rem;
}
.dnc-modal-background {
background-color: rgba(0, 0, 0, 0.4);
backdrop-filter: blur(15px);
}

Also read https://dotnetcoder.com/azure-key-vault-configuration-in-asp-net-core/
Using the Blazor Modal component in a Blazor Web App
In this section, we will learn how to use our custom Blazor Modal component in the Blazor application.
First, add a new Blazor Web App project template called Dnc.Modal.WebApp
to the solution. I have selected .NET 8 (Long Term Support) as the target Framework.
Second reference the Dnc.Common.Razor
project to the Dnc.Modal.WebApp
project, and update the _Imports.razor
as follows.
// Removed code for brevity
@using Dnc.Common.Razor.Modal
Then include the bootstrap link in the App.razor
file, as shown below.
<head>
// Removed code for brevity
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css">
<HeadOutlet @rendermode="InteractiveServer" />
</head>
Finally, add the following code to the HomeComponet.cs
file, I have separated the markup from the code in the Home component for clarity.
namespace Dnc.Modal.WebApp.Components.Pages
{
public class HomeComponent: ComponentBase
{
protected DncModal<Account> EditModal { get; set; }
protected DncModal<Account> AddModal { get; set; }
// Edit Modal Methods
protected void EditModalSubmitted(Account account)
{
var exist = Accounts.FirstOrDefault(v => v.Id == account.Id);
if (exist != null && EditModal.EditContext.Validate())
{
// Update the account in real projects
EditModal.Close();
}
}
protected void EditModalDisplayed(Account account)
{
EditModal.SetEditContext(new EditContext(account));
}
// Add Account Modal Methods
protected Account AccountModel { get; set; } = new Account()
{
Id = Guid.NewGuid().ToString(),
ExpireDate = DateTime.Now.AddYears(1)
};
protected void AddModalSubmitted(Account account)
{
var exist = Accounts.FirstOrDefault(v => v.Id == account.Id);
if (exist == null && AddModal.EditContext.Validate())
{
Accounts.Add(account);
AddModal.Close();
};
}
protected void AddModalDisplayed(Account account)
{
AddModal.SetEditContext(new EditContext(account));
}
protected List<Account> Accounts = new List<Account>
{
new Account {Id = Guid.NewGuid().ToString() , Name = "John Smith", Email= "john.smith@coder.com", Age = 20, ExpireDate = DateTime.Now.AddYears(1)},
new Account {Id = Guid.NewGuid().ToString() , Name = "Sarah Johnson", Email= "Sarah.Johnson@coder.com", Age = 30, ExpireDate = DateTime.Now.AddYears(1)},
new Account {Id = Guid.NewGuid().ToString() , Name = "Michael Brown", Email= "Michael.Brown@coder.com", Age = 40, ExpireDate = DateTime.Now.AddYears(1)},
new Account {Id = Guid.NewGuid().ToString() , Name = "Emily Davis", Email= "Emily.Davis@coder.com", Age = 50, ExpireDate = DateTime.Now.AddYears(1)}
};
}
public class Account
{
public string Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
[EmailAddress(ErrorMessage = "Insert valid email address")]
public string Email { get; set; }
[Range(18, 80, ErrorMessage = "The Age should be between 18 and 65 years")]
public int Age { get; set; }
public DateTime ExpireDate { get; set; }
}
}
I have defined two properties AddModal
and EditModal
because we need to use the Blazor Modal component as a variable, so we need a reference to it.
I will go through the code for creating a new account just for the sake for brevity.
protected void AddModalDisplayed(Account account)
{
AddModal.SetEditContext(new EditContext(account));
}
AddModalDisplayed
is responsible for setting the EditContext
in the Blazor Modal component with the SetEditContext
method in the DncModal
, as you can see in the code snippet above.
protected void AddModalSubmitted(Account account)
{
var exist = Accounts.FirstOrDefault(v => v.Id == account.Id);
if (exist == null && AddModal.EditContext.Validate())
{
Accounts.Add(account);
AddModal.Close();
};
}
The AddModalSubmitted
function is responsible for adding a new account and is triggered when the OnSubmit
event is triggered.
Finally add the following code to the file Home.razor
.
@page "/"
@inherits HomeComponent
<PageTitle>Home</PageTitle>
<div class="container mt-5 mx-auto">
<div class="row">
<div class="col pb-5">
<h3>Accounts</h3>
<table class="table">
<thead><tr><th>Name</th><th>Email address</th><th>Age</th><th>Expire date</th><th>#</th></tr></thead>
<tbody>
@foreach (var account in Accounts)
{
<tr>
<td>@account.Name</td>
<td>@account.Email</td>
<td>@account.Age</td>
<td>@account.ExpireDate.ToShortDateString()</td>
<td>
<button class="btn btn-warning px-3" @onclick="()=>EditModal.Show(account)">
Edit Account
</button>
</td>
</tr>
}
</tbody>
</table>
<button class="btn btn-success mt-3 px-3" @onclick="()=>AddModal.Show(AccountModel)">
Create Account
</button>
</div>
</div>
</div>
<DncModal TItem="Account"
@ref="EditModal"
OnSubmit="EditModalSubmitted"
OnShow="EditModalDisplayed"
Size="Medium">
<HeaderTemplate>
<h5>Edit <b>@context.Name</b> Account</h5>
</HeaderTemplate>
<BodyTemplate>
<DataAnnotationsValidator />
<div class="mb-3">
<label for="Name" class="form-label">Name</label>
<InputText class="form-control" id="Name" @bind-Value="context.Name" />
<ValidationMessage For="() => context.Name"></ValidationMessage>
</div>
<div class="mb-3">
<label for="Email" class="form-label">Email address</label>
<InputText class="form-control" id="Email" @bind-Value="context.Email" placeholder="name@example.com" />
<ValidationMessage For="() => context.Email"></ValidationMessage>
</div>
<div class="mb-3">
<label for="Age" class="form-label">Age</label>
<InputNumber class="form-control" id="Age" @bind-Value="context.Age"/>
<ValidationMessage For="() => context.Age"></ValidationMessage>
</div>
<div class="mb-3">
<label for="ExpireDate" class="form-label">Expire Date</label>
<InputDate class="form-control" id="ExpireDate" @bind-Value="context.ExpireDate" />
</div>
</BodyTemplate>
<FooterTemplate>
<button class="btn btn-secondary px-3" @onclick="()=>EditModal.Close()">Cancel</button>
<button class="btn btn-warning px-3" type="submit">Update the Account</button>
</FooterTemplate>
</DncModal>
<DncModal TItem="Account"
@ref="AddModal"
OnSubmit="AddModalSubmitted"
OnShow="AddModalDisplayed"
Size="Larg">
<HeaderTemplate>
<h5>Create a new Account</h5>
</HeaderTemplate>
<BodyTemplate>
<DataAnnotationsValidator />
<div class="mb-3">
<label for="Name" class="form-label">Name</label>
<InputText class="form-control" id="Name" @bind-Value="AccountModel.Name" />
<ValidationMessage For="() => context.Name"></ValidationMessage>
</div>
<div class="mb-3">
<label for="Email" class="form-label">Email address</label>
<InputText class="form-control" id="Email" @bind-Value="AccountModel.Email" placeholder="name@example.com" />
<ValidationMessage For="() => AccountModel.Email"></ValidationMessage>
</div>
<div class="mb-3">
<label for="Age" class="form-label">Age</label>
<InputNumber class="form-control" id="Age" @bind-Value="AccountModel.Age" />
<ValidationMessage For="() => AccountModel.Age"></ValidationMessage>
</div>
<div class="mb-3">
<label for="ExpireDate" class="form-label">Expire Date</label>
<InputDate class="form-control" id="ExpireDate" @bind-Value="AccountModel.ExpireDate" />
</div>
</BodyTemplate>
<FooterTemplate>
<button class="btn btn-secondary px-3" @onclick="()=>AddModal.Close()">Cancel</button>
<button class="btn btn-success px-3" type="submit">Create Account</button>
</FooterTemplate>
</DncModal>
We have defined a DncModal
and specified the methods to be triggered when the onSubmit
and OnShow
events are triggered, and added the HTML markup in the HeaderTemplate
and BodyTemplate
with validation.
In addition, we need a reference to the AddModal
Blazor Modal component using @ref
, which is used as a variable in the code to display and close the Modal.
The Size is optional, you can set the modal size to Small
, Medium (Default)
, Larg
or ExtraLarg
, as you see in the following code snippets.
<DncModal TItem="Account"
@ref="AddModal"
OnSubmit="AddModalSubmitted"
OnShow="AddModalDisplayed"
Size="Larg">
<button class="btn btn-success mt-3 px-3" @onclick="()=>AddModal.Show(AccountModel)">
Create Account
</button>
Set the Dnc.Modal.WebApp
as Startup project and run the application.

Add a new account and update an account with the Blazor Modal Component.


Conclusion
In this post, we created a Blazor Modal component that you can use in your various projects. We started by creating a Blazor class library and then added the Blazor modal dialog component code and markup to finally take a look at the Blazor Modal dialog component.
The code for the reusable Blazor Modal component can be found Here
Also read https://dotnetcoder.com/create-json-localization-service-blazor-server/
Enjoy This Blog?
Discover more from Dot Net Coder
Subscribe to get the latest posts sent to your email.