Creating a confirmation (“Are you sure?”) component in Blazor

Back in the Dark Ages (ie, before Blazor, when we had to write JavaScript, ugh), if you wanted to have the user confirm some data-changing action, such as deleting, you would use the JavaScript alert function…

alert("Are you sure you want to delete the entire database?");

I wanted to achieve the same effect in Blazor, so did some searching.

Sadly, all the results I found used JSInterop to call alert! Come on, we don’t write JavaScript nowadays! Well, I don’t if I can help it.

So, I decided to see if I could write a Blazor component to achieve the same end. As with everything Blazor, this turned out to be fairly simple, albeit with some CSS skills that were a bit beyond my level.

I started with a search for “CSS overlay”, which led me to a W3Schools page that showed how to do an overlay for the whole browser window. This was a good start.

I created a Blazor component named Confirm, and added the following content…

<div id="confirmOverlay" style="display: @_displayStyle">
  <div id="confirmOverlayContent">
    <p>@Caption</p>
    <button class="btn btn-primary" @onclick="@(() => ButtonClicked(true))">@YesText</button>
    <button class="btn btn-secondary" @onclick="@(() => ButtonClicked(false))">@NoText</button>
  </div>
</div>

@ChildContent

<style>
  #confirmOverlay {
    position: absolute;
    width: 100%;
    height: 100%;
    top: 0;
    left: 0;
    background-color: rgba(0, 0, 0, 0.5);
    z-index: 2;
  }

  #confirmOverlay #confirmOverlayContent {
    position: absolute;
    top: 50%;
    left: 50%;
    font-size: 18px;
    transform: translate(-50%, -50%);
    -ms-transform: translate(-50%, -50%);
    padding: 10px;
    background: #fff;
    color: #000;
    text-align: center;
    box-shadow: 10px 10px 5px #333;
    border-radius: 10px;
  }
</style>

@code {

  [Parameter]
  public string Caption { get; set; }

  [Parameter]
  public string YesText { get; set; } = "Yes";

  [Parameter]
  public string NoText { get; set; } = "No";

  [Parameter]
  public bool Result { get; set; }

  [Parameter]
  public EventCallback<bool> ResultChanged { get; set; }

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

  private string _displayStyle = "none";

  public void Display(string caption="") {
    if (!string.IsNullOrWhiteSpace(caption)) {
      Caption = caption;
    }
    _displayStyle = "block";
  }

  private async Task ButtonClicked(bool yes) {
    _displayStyle = "none";
    Result = yes;
    await ResultChanged.InvokeAsync(Result);
  }

}

I started off with the same CSS as in the W3Schools page, and it worked fine.

However, I wanted to be able to block off specific sections of a web page, not just the whole page, so needed some expert CSS help. Thankfully, my son was in the other room, so I drafted him in. He modified the CSS to look like the code above. The only downside to the current code is that you need to set the parent container’s display style to relative, which isn’t usually a problem, but you need to remember. I would have preferred a totally self-contained component.

So, if you wrap the part of the page you want in the new component, you can block it out. Here is a full sample Blazor page (obligatory lorem ipsum text added to fill up the container)…

@page "/ConfirmTest"

<h3>Confirm test</h3>
<p>Use this when you want to confirm some operation.</p>
<fieldset>
  <legend style="width: auto">Container for overlay</legend>
  <Confirm @ref="_confirm" ResultChanged="ResultChanged">
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi fermentum molestie massa, aliquam eleifend metus iaculis dictum.</p>
    <p>Etiam molestie ex augue, tincidunt aliquet odio tincidunt id. Suspendisse a lectus orci.</p>
    <button class="btn btn-primary" @onclick="DeleteDatabase">Click here to delete the database</button>
    <button class="btn btn-secondary" @onclick="DeleteTable">Click here to delete one table</button>
  </Confirm>
</fieldset>
<p>Confirmed?: @((MarkupString)_msg)</p>

<style>
  fieldset {
    border: 1px solid #000;
    padding: 20px;
    position: relative
  }
</style>

@code {
  private Confirm _confirm;
  private string _msg;

  private void DeleteDatabase() => _confirm.Display("Delete the database?");

  private void DeleteTable() => _confirm.Display("Delete one table?");

  private void ResultChanged(bool yes) => _msg = $"{yes}<br/>";

}

When the page loads, it looks like this…

If you click one of the buttons, you get the overlay as required…

If you click the Yes button, the parent page is updated…

As I said, I’m no CSS expert, and I’m sure this could be made to look a lot nicer, but that can come later. Similarly, you could add more properties to allow more fine-grained control over the overlay itself, but right at the moment, I have something that works as I need it. If you really yearn for something that looks like the JavaScript alert box (why?), I guess it wouldn’t be too hard to adjust the styling to do that.

I’m building up a nice collection of useful Blazor components now. Some day I intend to wrap them up in a Nuget package. Don’t hold your breath!

Be First to Comment

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.