How to use Bootstrap modal in Blazor client app?
Solution 1
There is likely a better way to do this, but here's a working example to get you started:
Page:
@page "/modal-test"
<BlazorApp1.Components.Modal @ref="Modal"></BlazorApp1.Components.Modal>
<button @onclick="() => Modal.Open()">Open Modal</button>
@code {
private BlazorApp1.Components.Modal Modal { get; set; }
}
Component:
<div class="modal @ModalClass" tabindex="-1" role="dialog" style="display:@ModalDisplay">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Modal title</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<p>Modal body text goes here.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary">Save changes</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal" @onclick="() => Close()">Close</button>
</div>
</div>
</div>
</div>
@if (ShowBackdrop)
{
<div class="modal-backdrop fade show"></div>
}
@code {
public Guid Guid = Guid.NewGuid();
public string ModalDisplay = "none;";
public string ModalClass = "";
public bool ShowBackdrop = false;
public void Open()
{
ModalDisplay = "block;";
ModalClass = "Show";
ShowBackdrop = true;
StateHasChanged();
}
public void Close()
{
ModalDisplay = "none";
ModalClass = "";
ShowBackdrop = false;
StateHasChanged();
}
}
Another option to go about this, would be to use JSInterop to call $('#modalId').modal()
You could have each version of the component have a unique id by doing something like this:
<div id="bootstrap-modal-@Guid"
then use the saved ID to call .modal() with jQuery.
Solution 2
Building on Kyle's answer, this is my first experiment with Blazor: Making the modal dialog component take any markup or component.
Modal.razor
<div class="modal @modalClass" tabindex="-1" role="dialog" style="display:@modalDisplay; overflow-y: auto;">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">@Title</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close" @onclick="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
@Body
</div>
<div class="modal-footer">
@Footer
</div>
</div>
</div>
</div>
@if (showBackdrop)
{
<div class="modal-backdrop fade show"></div>
}
@code {
[Parameter]
public RenderFragment Title { get; set; }
[Parameter]
public RenderFragment Body { get; set; }
[Parameter]
public RenderFragment Footer { get; set; }
private string modalDisplay = "none;";
private string modalClass = "";
private bool showBackdrop = false;
public void Open()
{
modalDisplay = "block;";
modalClass = "show";
showBackdrop = true;
}
public void Close()
{
modalDisplay = "none";
modalClass = "";
showBackdrop = false;
}
}
Index.razor
@page "/"
<h1>Hello, world!</h1>
Welcome to your new app.
<button class="btn btn-primary" @onclick="() => modal.Open()">Modal!</button>
<Modal @ref="modal">
<Title>This is a <em>Title!</em></Title>
<Body>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Omnes enim iucundum motum, quo sensus hilaretur.
<i>Quis istud possit, inquit, negare?</i>
<mark>Ego vero isti, inquam, permitto.</mark> Duo Reges: constructio interrete.
</p>
<FetchData />
<dl>
<dt><dfn>Stoici scilicet.</dfn></dt>
<dd>An hoc usque quaque, aliter in vita?</dd>
<dt><dfn>Erat enim Polemonis.</dfn></dt>
<dd>Quod cum accidisset ut alter alterum necopinato videremus, surrexit statim.</dd>
</dl>
</Body>
<Footer>
<button type="button" class="btn btn-primary">Save changes</button>
<button type="button" class="btn btn-secondary" data-dismiss="modal" @onclick="() => modal.Close()">Close</button>
</Footer>
</Modal>
@code {
private Modal modal { get; set; }
}
Solution 3
Also building on Kyle's answer, you can sustain the bootstrap fade effect if you place a short delay between the display and class adjustments.
@code {
...
public async Task OpenModal()
{
ModalDisplay = "block;";
await Task.Delay(100);//Delay allows bootstrap to perform nice fade animation
ModalClass = "show";
StateHasChanged();
}
public async Task CloseModal()
{
ModalClass = "";
await Task.Delay(250);
ModalDisplay = "none;";
StateHasChanged();
}
}
I also applied the ModalClass and ModalDisplay variables to the backdrop element too
<div class="modal-backdrop fade @ModalClass" style="display: @ModalDisplay"></div>
I believe bootstrap can better identify the state change that triggers the animation this way
Solution 4
With Kyle solution my Dialog do not close when i click on the backdrop.
I saw that it is a problem of z-index: the modal div has a z-index of 1050, and the backdrop div has 1040, in this way i was not able to click my backdrop.
I have moved the backdrop inside the dialog div and added to the modal-dialog div z-index > 1040
(ES: 1055)
I also added data-dismiss="modal" @onclick="() => Close()"
to the backdrop div and now it works as well as the "Close" button.
<div class="modal @ModalClass" tabindex="-1" role="dialog" style="display:@ModalDisplay">
<div class="modal-dialog" role="document" style="z-index:1055">
...
</div>
@if (ShowBackdrop)
{
<div class="modal-backdrop fade show" data-dismiss="modal" @onclick="() => Close()"></div>
}
</div>
Solution 5
for backdrop shadow only add fade class:
<div class="modal fade @ModalClass" tabindex="-1" role="dialog"
style="display:@ModalDisplay">
Sorush
I am a PhD in Computational Fluid Dynamics (Maths + Physics + Coding). My passion is numerical programming but I always try new technologies. I started coding with QBasic at high school then picked Fortran and C/C++ for university projects. High-performance computing is necessary for CFD codes that's why I know OpenMP and MPI. Every now and then I visit Python to use its math libraries. I have developed many numerical apps with WPF(C#+XAML MVVM pattern) and, recently, several projects with Razor pages and Blazor WebAssembly. Therefore, I always have questions and answers about those topics.
Updated on April 05, 2021Comments
-
Sorush about 3 years
I am trying to show bootstrap modal then bind its buttons. But I cannot pass the first step showing the modal. I am using Blazor client template of .net core 3.1. I have a page named Modal.razor which contains the bootstrap modal I found from getbootstrap.com.
@if (Show) { <div class="modal" tabindex="-1" role="dialog"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title">Modal title</h5> <button type="button" class="close" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">×</span> </button> </div> <div class="modal-body"> <p>Modal body text goes here.</p> </div> <div class="modal-footer"> <button type="button" class="btn btn-primary">Save changes</button> <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button> </div> </div> </div> </div> } @code { [Parameter] public bool Show { get; set; } = false; }
An I called the modal in the index.razor file
@page "/" <button @onclick="(()=>switchModal=!switchModal)">Switch Modal</button> <Modal Show="switchModal"/> @code{ bool switchModal = false; }
You might say StateHasChanged should be called here. But even if I copy and paste the modal code in the index.razor, I won't see anything.