How to Create a Toast Message UI with JavaScript and CSS
A toast message is a small, self-dismissing pop-up notification used to provide quick feedback or brief information about an operation. It typically appears at the bottom of the screen and disappears automatically without interrupting the user's workflow. While these are very common in mobile devices, we will explore how to create our own toast message UI for web applications.
Look at the following example. Click the button to generate a toast message and see how it appears. And try clicking frequently to see how multiple toast messages will behave.
First, we need an HTML element to maintain all the toast messages. Since toast messages are dynamically created while their execution time, we are only going to need this element initially.
<!-- toast messages container -->
<div class="toast-tray"></div>
This tray element should be placed at the bottom of the screen, mostly on the left side. Therefore, we
can have some CSS as follows to make that happen. And the flex rules will arrange toast messages in a
vertical direction, one on top of another.
/* toast container */
.toast-tray {
/* placements */
position: fixed;
/* attach on bottom left of screen */
left: 0px;
bottom: 0px;
/* placement and spacing for items */
display: flex;
flex-direction: column;
padding: 0px 10px;
}
Now we need two CSS keyframe animations to handle the toast message animations. One for fade in
and one for fade out. Fade in will start from no opacity, and will be placed
below than usual. So when the fade-in animation ends, it will have to have full opacity, correct
placement, while acting as a fade-in bottom-to-top direction animation. The final 10px of
margin is to create the gap between each toast message. We are not creating that gap on the tray element, so we can
decrease it individually when they disappear.
/* fade in animation */
@keyframes toast-fade-in {
from {
opacity: 0;
margin-bottom: -20px;
}
to {
opacity: 1;
margin-bottom: 10px;
}
}
So in the fade-out disappearance animation, we reduce the opacity back to 0 and decrease
the height to 0px. Also, we need to clear the gap of clearing items by reducing the
margin-bottom amount. This way we can dismiss the toast message while
reducing its full height to zero.
/* fade out animation */
@keyframes toast-fade-out {
from {
opacity: 1;
height: 48px;
margin-bottom: 10px;
}
to {
opacity: 0;
height: 0px;
margin-bottom: 0px;
}
}
We can have some CSS for the toast message. We should have the fade-in animation initially on the toad message
element. An important thing is to set the iteration count to 1 and fill mode to forwards
so the animation only runs once and stops at the last state without resetting. In the same way, we can
have the fade-out animation, where we can close it later by setting an attribute on that, like
data-closed. We need to handle that part in JavaScript. Also, remember to
hide the overflowing content, so reducing height will work correctly, as in the above animation rules.
/* toast message */
.toast-message {
/* spacing */
height: 48px;
padding: 0px 20px;
overflow: hidden;
/* text styles */
color: #fff;
line-height: 48px;
/* initial appearance */
margin-bottom: -20px;
opacity: 0;
/* decorations */
background-color: #555;
border-radius: 10px;
user-select: none;
/* animation configurations */
animation-name: toast-fade-in;
animation-duration: 0.5s;
animation-iteration-count: 1;
animation-fill-mode: forwards;
}
/* closed toast message */
.toast-message[data-closed] {
animation-name: toast-fade-out;
animation-duration: 0.3s;
animation-iteration-count: 1;
animation-fill-mode: forwards;
animation-timing-function: linear;
}
Finally, we can write the JavaScript code and have a global function to create toast messages. We simply create a
div element, and the class name and message content on it. To place the newest messages on top of previous messages,
we can use the prepend method on the tray element. The fade-in animation will work automatically because of
the CSS we had. Then we wait for a while so the user will have some time to read the message. Later, we will use the
data-closed attribute, and the fade-out animation will work. Since the fade-out animation duration we set is
300ms, we wait that amount of time and remove the element from the tray. For these time delays, we can
simply use the setTimeout method.
// get toast tray element
const toastTray = document.querySelector(".toast-tray")
const createToast = message => {
// create toast element
const toastItem = document.createElement("div")
// set class name
toastItem.className = "toast-message"
// set message content
toastItem.innerHTML = message
// append on tray element
toastTray.prepend(toastItem)
// toast appearance delay
setTimeout(() => {
// set closed attribute
toastItem.setAttribute("data-closed", true)
// remove after fade out animations
setTimeout(() => toastItem.remove(), 300)
}, 2500)
}
// example usage
createToast("This is an example toast message")