I am new to Blazor and a replacement for JavaScript Alert, Confirm, and Prompt was one of the first things on my list. I came up with a service in Blazor Server / BlazorWebView (I haven't tested in Web Assembly). The <Modal> component we'll create can be controlled by the service or directly from JavaScript. Although, if you don't need to call the <Modal> via JavaScript than you can remove any JavaScript or IJSRuntime references.
The ModalService.cs is very simple. It has an OnShow event that we can hook into our <Modal> component later. The event is a function that takes prameters ModalType, title, body and it returns a dynamic task.
Setup
ModalService.cs
namespace MyProjectName.Services
{
    public class ModalService
    {
        
        public event Func<ModalBase.ModalType, string, string,Task<dynamic>> OnShow;
        public async Task<dynamic> Show(ModalBase.ModalType mType, string title, string body)
        {
            if(OnShow != null)
                return await OnShow?.Invoke(mType, title, body);
            return null;
        }
    }
}
The ModalBase.cs will be inherited by our <Modal> component. It handles opening and closing the modal. Here is where we can also attach to the ModalService event OnShow and hook up support for JavaScript invoking.
ModalBase.cs
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
namespace MyProjectName.Services
{
    public class ModalBase : ComponentBase, IDisposable
    {
        [Inject] ModalService ModalService { get; set; }
        [Inject] IJSRuntime JS { get; set; }
        public enum ModalType
        {
            Alert,
            Prompt,
            Confirm
        }
        protected override void OnInitialized()
        {
            // Attach to our service event.
            ModalService.OnShow += Show;
        }
        protected override async Task OnAfterRenderAsync(bool firstRender)
        {
            // Set a JavaScript referene for our DotNet interop.
            if(firstRender)
                await JS.InvokeVoidAsync("MODAL.SetDotnetReference", DotNetObjectReference.Create(this));
        }
        public string Title { get; set; }
        public string Body { get; set; }
        public Guid Guid = Guid.NewGuid();
        public string ModalDisplay = "none;";
        public string ModalClass = "";
        public bool ShowBackdrop = false;
        public string PromptValue { get; set; }
        private bool ConfirmValue { get; set; }
        public ModalType MType { get; set; }
   
      
        private List<string> MsgIds = new List<string>();
        [JSInvokable("Show")]
        public async Task<dynamic> Show(ModalType mType, string title, string body)
        {
            // The JavaScript call MODAL.DotNetReference.invokeMethodAsync is non-blocking
            // This means multiple calls to show the modal using invokeMethodAsync will only show the modal once.
            // We can solve this by making sure each message waits in line.
            string msgId = Guid.NewGuid().ToString();
            if (!MsgIds.Contains(msgId))
                MsgIds.Add(msgId);
            // If multiple messages are being processed, wait for this msgs turn.
            while (MsgIds.Count > 1 && MsgIds.IndexOf(msgId) != 0)
                await Task.Delay(250);
            Title = title;
            Body = body;
            ModalDisplay = "block;";
            ModalClass = "Show";
            MType = mType;
            ShowBackdrop = true;
            StateHasChanged();
            while (ShowBackdrop)
                await Task.Delay(250);
            switch (mType)
            {
                default:
                case ModalType.Alert:
                    MsgIds.Remove(msgId);
                    return string.Empty;
                case ModalType.Confirm:
                    bool confirmResponse = ConfirmValue;
                    MsgIds.Remove(msgId);
                    return confirmResponse;
                case ModalType.Prompt:
                    string promptResponse = PromptValue;
                    MsgIds.Remove(msgId);
                    return promptResponse;
            }
        }
        public void Close(bool isCancel)
        {
            // Determine returned values.
            PromptValue = isCancel ? string.Empty : PromptValue;
            ConfirmValue = isCancel ? false : true;
            ModalDisplay = "none";
            ModalClass = "";
            ShowBackdrop = false;
            StateHasChanged();
        }
        public void Dispose()
        {
            ModalService.OnShow -= Show;
        }
    }
}
I designed the <Modal> component based off the bootstrap markup discussed here. The major difference is I that have moved the guts into ModalBase.cs to interact with our service.
Modal.razor
@using Microsoft.JSInterop
@using MyProjectName.Services
@inherits ModalBase
<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 w-100 text-center" style="padding-left:31px">@Title</h5>
                <button type="button" class="close border-0 bg-white" data-dismiss="modal" aria-label="Close"  @onclick="() => Close(true)">
                    <span aria-hidden="true">×</span>
                </button>
            </div>
            <div class="modal-body mx-auto text-center text-break">
                @Body
                @if (MType == ModalType.Prompt){ 
                    <input type="text" class="form-control text-center my-2" @bind-value="PromptValue" style="max-width:400px"></input> 
                }
            </div>
            <div class="modal-footer justify-content-center">
                @if (MType == ModalType.Prompt || MType == ModalType.Confirm)
                {
                    <button type="button" class="btn btn-secondary" data-dismiss="modal" @onclick="() => Close(false)">OK</button>
                    <button type="button" class="btn btn-secondary" data-dismiss="modal" @onclick="() => Close(true)">Cancel</button>
                }
                else
                {
                    <button type="button" class="btn btn-secondary" data-dismiss="modal" @onclick="() => Close(false)">Close</button>
                }
            </div>
        </div>
    </div>
</div>
@if (ShowBackdrop)
{
    <div class="modal-backdrop fade show"></div>
}
Usage
Include the ModalService into our service collection.
Program.cs
builder.Services.AddScoped<ModalService>();
MainLayout.razor
@using MyProjectName.Components    
@inherits LayoutComponentBase
<PageTitle>My Project</PageTitle>
<Modal></Modal>
<div class="page">
    .
    .
    .
</div>
Inject and use the service somewhere in your application.
Index.razor
@code
{
    [Inject] public ModalService ModalService { get; set; }
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            if (await ModalService.Show(Modal.ModalType.Confirm,"Save Settings", "Are you sure you want to save settings?"))
            {
                string fileName = await ModalService.Show(Modal.ModalType.Prompt, "File Name", "Please enter a filename");
                if (!string.IsNullOrEmpty(fileName))
                    await ModalService.Show(Modal.ModalType.Alert, "File Saved Success", $"File Saved as {fileName}");
                else
                    await ModalService.Show(Modal.ModalType.Alert, "File Saved Cancelled", $"No file name was entered.");
            }
        }
     //   return base.OnAfterRenderAsync(firstRender);
    }
}
JavaScript Usage
// Defined somewhere globally
var MODAL = {};
MODAL.DotNetReference = null;
MODAL.SetDotnetReference = function (pDotNetReference) {
    MODAL.DotNetReference = pDotNetReference;
};
MODAL.MType = {
    Alert: 0,
    Prompt:1,
    Confirm: 2,
};
// Called from wherever
MODAL.DotNetReference.invokeMethodAsync('Show', MODAL.MType.Prompt, `Title goes here`, `Body goes here`)
.then(data => {
    console.log(`Prompt Response`, data);
});
JavaScript Note: Polyfil recommended for promise support in older browsers
Note: If you need to show the modal at earlier points in the application lifecycle, such as OnInitializedAsync, than you'll need to change ServerPrerendered to Server.
@*<component type="typeof(App)" render-mode="ServerPrerendered" />*@
<component type="typeof(App)" render-mode="Server" />