Using toast notifications in ASP.NET Core Razor Pages
Karen Payne
Posted on June 19, 2023
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">
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>
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; }
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";
}
}
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());
}
Results
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.
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>
Using JavaScript to display the toast above.
$("#toastButton1").click(function () {
$("#toast1").toast("show");
});
Asking a 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>
Add a property to the page which will be set in JavaScript.
[BindProperty]
public bool TakeAction { get; set; }
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();
});
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());
}
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>
}
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
Simple setup
private readonly INotyfService _toastNotificationService;
public ToastPageModel(ILogger<ToastPageModel> logger, INotyfService toastNotificationService)
{
_toastNotificationService = toastNotificationService;
}
Usage
Add a button
<input type="submit" class="btn btn-success" value="Success"
asp-page-handler="SuccessNotification"/>
Add a Post event
public void OnPostSuccessNotification()
{
_toastNotificationService.Success("Work finished");
}
Customized version
public void OnPostCustomNotification()
{
_toastNotificationService.Custom(
message: "Email sent",
durationInSeconds: 2,
backgroundColor: "black",
iconClassName: "fa fa-gear");
}
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.
Posted on June 19, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.