DEV Community

Cover image for Using toast notifications in ASP.NET Core Razor Pages
Karen Payne
Karen Payne

Posted on • Updated on

Using toast notifications in ASP.NET Core Razor Pages

The purpose of a toast allows users to know that their action was acknowledged or that something happened like an email has arrived in a polite manner.

Note
From Bootstrap: Toasts are lightweight notifications designed to mimic the push notifications that have been popularized by mobile and desktop operating systems.

Code samples

There are plenty of code samples which interact between HTML, JavaScript and C# unlike other code samples on the web which generally exclude C#.

Libraries

In this article several libraries will be presented with favor towards Bootstrap as Bootstrap supports Accessibility while the other libraries do not support Accessibility. Accessibility is very important as without making a web site accessible customers may be lost.

Bootstrap

To get started, read the documentation for toast.

✔️ One of the major benefits for Bootstrap is its suitable for screen readers which is discussed in Bootstrap documentation while the other libraries are not capable of working with screen readers.

Typically one sees toast in the bottom right hand corner of a page and the same for Windows Desktop toast.

Example, create a container for a toast

<div class="toast-container position-fixed bottom-0 end-0 p-3" style="z-index: 11">
Enter fullscreen mode Exit fullscreen mode

position-fixed bottom-0 end-0 tells Bootstrap to position a toast in the bottom right hand corner of a page.

Add a toast to the above container

<div class="toast text-white bg-danger border-0" 
     id="bottomToast" 
     role="alert" 
     aria-live="assertive" 
     aria-atomic="true">

    <div class="d-flex">
        <div class="toast-body">
            @Model.Bottom
        </div>
        <button type="button" 
                class="btn-close btn-close-white me-2 m-auto" 
                data-bs-dismiss="toast"
                aria-label="Close"></button>
    </div>
</div>
Enter fullscreen mode Exit fullscreen mode

Model for setting the body text of the toast.

public class MessageContainer
{
    public string Top { get; set; }
    public string Bottom { get; set; }
}

...

[BindProperty]
public MessageContainer MessageContainer { get; set; }
Enter fullscreen mode Exit fullscreen mode

In OnGet the code is setup to receive text for two toast and if not pasted has defaults. In the code sample, on the Index Page there are two inputs which when submitting the form redirects to the Privacy page passing data via Json while going directly to the Privacy page the default data is used.

public void OnGet(string containers)
{
    MessageContainer = new MessageContainer();

    if (!string.IsNullOrWhiteSpace(containers))
    {
        List<ToastContainer>? data = JsonSerializer.Deserialize<List<ToastContainer>>(containers);

        MessageContainer.Top = data.FirstOrDefault(x => x.Name == "Top").Body;
        MessageContainer.Bottom = data.FirstOrDefault(x => x.Name == "Bottom").Body;
    }
    else
    {
        MessageContainer.Top = "Top message";
        MessageContainer.Bottom = "Bottom message";
    }
}
Enter fullscreen mode Exit fullscreen mode

To display the toast, the following JavaScript is used.

function bottomToast() {
    var toastElList = [].slice.call(document.querySelectorAll('#bottomToast'));
    var toastList = toastElList.map(function (toastEl) {
        return new bootstrap.Toast(toastEl);
    });
    toastList.forEach(toast => toast.show());
}
Enter fullscreen mode Exit fullscreen mode

Results

Displaying bottom toast

Center toast on a page

Although toast as generally displayed in the bottom right hand corner of a page, they can be positioned top or centered on a page.

Displaying toast center page

For the above we use several Bootstrap classes and set the height of a div container.

<div aria-live="polite" 
     aria-atomic="true" 
     class="d-flex justify-content-center align-items-center w-100" 
     style="height: calc(100vh - 125px - 125px);">

    <div class="toast bg-danger"
         role="alert"
         aria-live="assertive"
         aria-atomic="true"
         id="toast1">

        <div class="toast-header">

            <strong class="me-auto">Alert</strong>
            <small>code sample</small>

            <button type="button" 
                    class="btn-close" 
                    data-bs-dismiss="toast" 
                    aria-label="Close"></button>
        </div>

        <div class="toast-body text-white">
            This toast is centered on the page
        </div>

    </div>
</div>
Enter fullscreen mode Exit fullscreen mode

Using JavaScript to display the toast above.

$("#toastButton1").click(function () {
    $("#toast1").toast("show");
});
Enter fullscreen mode Exit fullscreen mode

Asking a question

toast asking yes no question

Here we add two buttons to the toast body with identifiers.

<div class="toast" 
     role="alert" 
     id="buttonExample"
     aria-live="assertive" 
     aria-atomic="true">
    <div class="toast-body">
        Click [Take action] button!
        <div class="mt-2 pt-2 border-top">

            <button type="button"
                    class="btn btn-primary btn-sm"
                    id="takeAction">
                Take action
            </button>

            <button type="button"
                    class="btn btn-secondary btn-sm"
                    id="noAction"
                    data-bs-dismiss="toast">
                Close
            </button>

        </div>
    </div>
</div>
Enter fullscreen mode Exit fullscreen mode

Add a property to the page which will be set in JavaScript.

[BindProperty]
public bool TakeAction { get; set; }
Enter fullscreen mode Exit fullscreen mode

JavaScript to handle the two buttons click events.

document.getElementById("takeAction").addEventListener("click", function () {
    document.getElementById("takeActionValue").value = true;
    document.getElementById("form1").submit();
});

document.getElementById("noAction").addEventListener("click", function () {
    document.getElementById("takeActionValue").value = false;
    document.getElementById("form1").submit();
});
Enter fullscreen mode Exit fullscreen mode

Then OnPost, in this case using SeriLog display yes or no where YesNo is a language extension.

public void OnPost()
{
    Log.Information("Take action {A}", TakeAction.ToYesNo());
}
Enter fullscreen mode Exit fullscreen mode

Using an alert

There is always the option to use an dismissing Alert which in the example below waits three seconds than displays.

@page
@model IndexModel
@{
    ViewData["Title"] = "Home page";
}

<div class="container">
    <div class="alert alert-primary alert-dismissible fade show d-none"
         role="alert"
         id="customAlert">

        <strong>Attention</strong> time to take a break.
        <button type="button" class="btn-close" 
                data-bs-dismiss="alert" 
                aria-label="Close"></button>

    </div>
</div>

@section Scripts
{
    <script>
        document.addEventListener("DOMContentLoaded", handleClick);

        async function handleClick() {
            await new Promise((resolve) => setTimeout(resolve, 3000));
            document.querySelector("#customAlert").classList.remove("d-none");
        }
    </script>
}
Enter fullscreen mode Exit fullscreen mode

AspNetCoreHero.ToastNotification

ToastNotification is a Minimal & Elegant Toast Notification Package for ASP.NET Core Web Applications that can be invoked via C#. Compatilble with ASP.NET Core 3.1 and .NET 5. (works with .NET Core 6 and .NET Core 7).

  • Not WCAG complaint
  • Not the best documentation

AspNetCoreHero page

Simple setup

private readonly INotyfService _toastNotificationService;
public ToastPageModel(ILogger<ToastPageModel> logger, INotyfService toastNotificationService)
{
    _toastNotificationService = toastNotificationService;
}
Enter fullscreen mode Exit fullscreen mode

Usage

Add a button

<input type="submit" class="btn btn-success"  value="Success"
       asp-page-handler="SuccessNotification"/>
Enter fullscreen mode Exit fullscreen mode

Add a Post event

public void OnPostSuccessNotification()
{
    _toastNotificationService.Success("Work finished");
}
Enter fullscreen mode Exit fullscreen mode

Customized version

public void OnPostCustomNotification()
{
    _toastNotificationService.Custom(
        message: "Email sent", 
        durationInSeconds: 2, 
        backgroundColor: "black", 
        iconClassName: "fa fa-gear");
}
Enter fullscreen mode Exit fullscreen mode

Wrapping it up

The clear choice for robust toast that are WCAG compliant is Bootstrap. There are others that are paid for such as Kendo notifications which I have a sample here.

Everyone will have their own choice which is why in the provided source code there are several other libraries that can be tried out.

Requires

  • Microsoft Visual Studio 2022 or higher
  • .NET Core 7 (with minor changes like scoped namespaces will worjk with .NET Core 6)

Source code

Clone the following GitHub repository.

There is a lot more code than presented in this article.

Caveats

In several pages CSS and JavaScript has been nested. The JavaScript is kind of bleeding edge as sometimes the code gets cached and/or Visual Studio complains about overwriting a file.

nested files

Top comments (0)