Displaying Dynamic Messages Using the Web Notification API was peer reviewed by Julian Motz. Thanks to all of SitePoint’s peer reviewers for making SitePoint content the best it can be!
We live in a world where notifications from your favorite websites or applications no longer exist within the confines of your smartphone. It is now commonplace to receive notifications directly from your browser. For example, Facebook sends you notifications if you have a new friend request or someone comments on a story where you are mentioned. Slack, a popular messaging app, sends you notifications when you are mentioned in a conversation.
As a front-end developer, I was curious how I could leverage browser notifications for websites that are not dealing with large streams of information. How can I add browser notifications that are relevant to the visitor based on their interest in my website?
In this article, we will implement a notification system on the Concise CSS website that will alert visitors every time a new version of the framework is released. I’m going to show you how I accomplished this by using localStorage with the browser Notification API.
Basics of the Notification API
To begin, we need to determine if notifications are supported by the visitor’s web browser. The brunt of the work throughout this tutorial will by done by the notification object.
(function() {
if ("Notification" in window) {
}
})();
So far we have only determined if notifications are supported by our visitor’s browser. After we have established that, we need to know if we can display permissions to the visitor.
We store the output of the permission
property in a variable. If permission is granted or denied, we return nothing. If we have not requested permission before, we do so with the requestPermission method.
(function() {
if ("Notification" in window) {
var permission = Notification.permission;
if (permission === "denied" || permission === "granted") {
return;
}
Notification.requestPermission();
}
})();
You should see a notice in your web browser similar to the image above.
Now that we’ve asked for permission, let’s modify our code to display a notification if permission is allowed:
(function() {
if ("Notification" in window) {
var permission = Notification.permission;
if (permission === "denied" || permission === "granted") {
return;
}
Notification
.requestPermission()
.then(function() {
var notification = new Notification("Hello, world!");
});
}
})();
Uninspiring, but functional.
Here we use the promise-based syntax of the requestPermission()
method to display a notification after permission has been granted. We display the notification using the notification constructor. This constructor takes two parameters, one for a notification title, and one for options. Follow the link to the documentation to find a complete list of options that can be passed.
Storing Framework Versions
Earlier in the article, I mentioned that we would be using localStorage to help us display notifications. Using localStorage is the preferred method of storing persistent client-side information in JavaScript. We will be creating a localStorage key named conciseVersion
that will contain the current version of the framework (e.g. 1.0.0). We can then use this key to check for new versions of the framework.
How do we update the value of our conciseVersion
key with the latest version of the framework? We need a way of setting the current version whenever someone visits the website. We also need to update that value whenever a new version is released. Every time the conciseVersion
value changes, we need to display a notification to the visitor announcing a new version of the framework.
We’re going to solve this problem by adding a hidden element to the page. This element will have a class named js-currentVersion
and will only contain the current version of the framework. Because this element exists in the DOM, we can easily interact with it using JavaScript.
This hidden element will be used to store the framework version in our conciseVersion
key. We will also use this element to update that key whenever a new version of the framework is released.
<span class="js-currentVersion" aria-hidden="true">3.4.0</span>
We can use a small bit of CSS to hide this element:
[aria-hidden="true"] {
display: none;
visibility: hidden;
}
Note: Since this element contains no meaningful content, it is unnecessary for screen readers to access this element. This is why I have set the aria-hidden attribute to
true
and have useddisplay: none
as the means of hiding the element. Please refer to this WebAIM article for more information on hiding content.
Now we can take this element and interact with it in JavaScript. We need to write a function that returns the text inside of the hidden element we just created.
function checkVersion() {
var latestVersion = document.querySelector(".js-currentVersion").textContent;
}
This function stores the content of the .js-currentVersion
element by using the textContent property. Let’s add another variable that will store the content of our conciseVersion
localStorage
key.
function checkVersion() {
var latestVersion = document.querySelector(".js-currentVersion").textContent;
var currentVersion = localStorage.getItem("conciseVersion");
}
Now we have the latest version of our framework in a variable, and we are storing our localStorage
key to a variable. It’s time to add the logic that determines if there’s a new version of the framework available.
We first check to see if the conciseVersion
key exists. If it does not, we will display a notification to the user, as it’s likely their first time visiting. If the key does exist, we check that its value (stored in the currentVersion
variable) is greater than that of the current version (stored in the latestVersion
variable). If the latest version of the framework is greater than the version the visitor last saw, we know that a new version has been released.
Note: We’re using the semver-compare library to handle comparing the two version strings.
Knowing this, we display a notification to the visitor and update our conciseVersion
key appropriately.
function checkVersion() {
var latestVersion = document.querySelector(".js-currentVersion").textContent;
var currentVersion = localStorage.getItem("conciseVersion");
if (currentVersion === null || semverCompare(currentVersion, latestVersion) === -1) {
var notification = new Notification("Hello, world!");
localStorage.setItem("conciseVersion", latestVersion);
}
}
To use this function, we’ll need to modify our permission code below.
(function() {
if ("Notification" in window) {
var permission = Notification.permission;
if (permission === "denied") {
return;
} else if (permission === "granted") {
return checkVersion();
}
Notification.requestPermission().then(function() {
checkVersion();
});
}
})();
This allows us to display notifications if the user has granted permission previously or if permission has just been granted.
Displaying Notifications
So far, we have only displayed simple notifications to the user that don’t contain much information. Let’s write a function that allows us to create browser notifications on the fly, and control the many different aspects of our notification.
This function has parameters for body text, icon, title as well as an optional link and notification duration. Inside, we create an options object that stores both our notification body text and icon. We also create a new instance of the Notification
object, passing in the title of our notification as well as the options object.
Next, we add an onclick
handler if we want to link to our notification. We use setTimeout()
to close the notification after whatever time has been specified. If no time is specified when calling this function, a default of five seconds is used.
function displayNotification(body, icon, title, link, duration) {
link = link || null; // Link is optional
duration = duration || 5000; // Default duration is 5 seconds
var options = {
body: body,
icon: icon
};
var n = new Notification(title, options);
if (link) {
n.onclick = function () {
window.open(link);
};
}
setTimeout(n.close.bind(n), duration);
}
Now, let’s modify checkVersion()
to display a more informative notification to the user.
function checkVersion() {
var latestVersion = document.querySelector(".js-currentVersion").textContent;
var currentVersion = localStorage.getItem("conciseVersion");
if (currentVersion === null || semverCompare(currentVersion, latestVersion) === -1) {
displayNotification(
`Click to see what's new in v${latestVersion}`,
"http://concisecss.com/images/logo.png",
"A new version of Concise is available",
`https://github.com/ConciseCSS/concise.css/releases/v${latestVersion}`
);
localStorage.setItem("conciseVersion", latestVersion);
}
}
We use our displayNotification
function to provide a description, image, title and link for our notification.
Note: we are using ES6 template literals to embed expressions within our text.
Complete Code and Testing
Below you can see the complete code that we’ve written in this tutorial.
See the Pen Implementing Dynamic Browser Notifications by SitePoint (@SitePoint) on CodePen.
Running this code should produce the following notification in your browser.
For testing, you will need to be familiar with notification permissions for your browser. Here are some quick references for managing notifications in Google Chrome, Safari, FireFox, and Microsoft Edge. Additionally, you should be familiar using the developer console to delete and modify localStorage
values for ease of testing.
You can test the example by running the script one time and changing the value of the js-currentVersion
HTML element so that the script sees the difference. You can also re-run using the same version to confirm that you don’t receive unnecessary notifications.
Taking it Further
That’s all we need to have dynamic browser notifications! If you are looking for more flexibility with your browser notifications, I suggest learning about the Service Worker API. Service workers can be used to react to push notifications that allow the user to become notified, regardless of whether or not they are currently visiting your website, resulting in more timely updates.
If you have any questions, comments or feedback feel free to leave them in the comments below. I would also love to see any examples of how you’ve incorporated JavaScript notifications into your projects.