How to create toasts using bootstrap 5

Updated: 6th December 2022
Tags: javascript bootstrap5 css

b5toastjs (method 1)

While using bootstrap 5 I wanted to ditch toastr and everything that was tied to jquery.
Besides, why do I need a big library if my goal is to show simple toast in the bottom left.

So I checked documentation to bootstrap 5. That was weird. Bootstrap 5 docs with live toast didn’t work as expected.
Anyway, I wanted to go fancy - to create multiple toasts like my beloved toastr did.

For toast to show we need to create that element and place in toast container.

<div class="position-fixed bottom-0 start-0 p-3" id="toast-container"></div>

and some js to create

//0. get our container
const toastContainerElement = document.getElementById("toast-container");
const delay = 10000;

const myToast = {
    //here the core function.
    //1. We get color, message and optional title
    show: function (color, message, title) {
        title = title ? title : '';
        const html =
    `<div class="toast align-items-center mt-1 text-white bg-${color} border-0" role="alert" aria-live="assertive" aria-atomic="true">
        <div class="d-flex">
            <div class="toast-body">
                <b>${title}</b>
                <div>${message}</div>
            </div>
            <button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
        </div>
    </div>`;
        //2. We create toast element from template above^
        const toastElement = htmlToElement(html);
        //3. We place toast elemet into container
        toastContainerElement.appendChild(toastElement);
        //4. Wrap toast into bootstrap toast (for fancy animation, etc)
        const toast = new bootstrap.Toast(toastElement, { delay: delay, animation: true });
        toast.show();
        //5. remove toast after delay + 3seconds to allow fancy bootstrap animation
        setTimeout(() => toastElement.remove(), delay + 3000);
    },

    //helper functions for lazy people
    error: function (message, title) {
        myToast.show('danger', message, title);
    },
    success: function (message, title) {
        myToast.show('success', message, title);
    }
};

//helper function
function htmlToElement(html) {
    var template = document.createElement('template');
    html = html.trim();
    template.innerHTML = html;
    return template.content.firstChild;
}

So I created my function 2 years ago. But yesterday I decided to share it and make it as simple library script.

It is the same but wrapped in b5toast object and added optional delay. Here final js code:

const b5toastContainerElement = document.getElementById("toast-container");

const b5toast = {
    delayInMilliseconds: 7000,
    htmlToElement: function (html) {
        const template = document.createElement("template");
        html = html.trim();
        template.innerHTML = html;
        return template.content.firstChild;
    },
    show: function (color, message, title, delay) {
        title = title ? title : "";
        const html = `<div class="toast align-items-center mt-1 text-white bg-${color} border-0" role="alert" aria-live="assertive" aria-atomic="true">
        <div class="d-flex">
            <div class="toast-body">
                <b>${title}</b>
                <div>${message}</div>
            </div>
            <button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
        </div>
    </div>`;
        const toastElement = b5toast.htmlToElement(html);
        b5toastContainerElement.appendChild(toastElement);
        const toast = new bootstrap.Toast(toastElement, {
            delay: delay?delay:b5toast.delayInMilliseconds,
            animation: true
        });
        toast.show();
        setTimeout(() => toastElement.remove(), delay?delay:b5toast.delayInMilliseconds + 3000);
    },

    error: function (message, title, delay) {
        b5toast.show("danger", message, title, delay);
    },
    success: function (message, title, delay) {
        b5toast.show("success", message, title, delay);
    },
};

Source code b5toast
Demo b5toast

The shortest usage is to include container and script and run b5toast.success('my message'); There are optional title and delay in docs to library.

b5toastSingle (method 2)

Funny story. I wanted to make other more simple version with reusing single bootstrap toast. But their example was broken.

//beware broken example. will have some glitches when running new toast if previous is at the end of his life
const toastTrigger = document.getElementById('liveToastBtn')
const toastLiveExample = document.getElementById('liveToast')
if (toastTrigger) {
  toastTrigger.addEventListener('click', () => {
    const toast = new bootstrap.Toast(toastLiveExample)

    toast.show()
  })
}

Few days I didn’t get why they don’t fix it, and somehow I did fix it for them. On button click, they wrap element in their toast functionality and show. So I tried to move wrapping up. And eureka! This fixed toast’ glitches. Here fixed example.

//fixed version by js noob, me xD
const toastTrigger = document.getElementById('liveToastBtn');
const toastLiveExample = document.getElementById('liveToast');
const toastBootstrap = new bootstrap.Toast(toastLiveExample);
if (toastTrigger) {
    toastTrigger.addEventListener('click', () => {
        toastBootstrap.show();
    });
}

Anyway, here my b5toastSingle function demo

Basically we place html at the bottom of page

<div class="toast-container position-fixed bottom-0 start-0 p-3">
  <div id="b5toastSingle" class="toast align-items-center mt-1 text-white bg-success border-0" role="alert"
       aria-live="assertive" aria-atomic="true">
    <div class="d-flex">
      <div class="toast-body">
        <b id="b5toastSingleTitle"></b>
        <div id="b5toastSingleMessage"></div>
      </div>
      <button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast"
              aria-label="Close"></button>
    </div>
  </div>
</div>

And add 18 lines of js

(function () {
    const b5toastSingle = document.getElementById('b5toastSingle');
    const b5toastSingleTitle = document.getElementById('b5toastSingleTitle');
    const b5toastSingleMessage = document.getElementById('b5toastSingleMessage');
    const colorsUsed = ['bg-success', 'bg-primary', 'bg-info', 'bg-danger', 'bg-warning'];

    const b5toastSingleElementToast = new bootstrap.Toast(b5toastSingle, {
      delay: 5000,
      animation: true
    });
    window['b5toastSingle'] = function (color, message, title) {
      title = title ? title : "";
      b5toastSingleTitle.innerHTML = title;
      b5toastSingleMessage.innerHTML = message;
      b5toastSingle.classList.remove(...colorsUsed);
      b5toastSingle.classList.add('bg-'+color);
      b5toastSingleElementToast.show();
    }
  })();

Not sure if it is better than b5toast.js, but it works. Only one toast at a time, but who needs more? Material design guys say only one snackbar should be shown at any moment.

Choose what you like I go with b5toast.js as I wanna go fancy with multiple toasts xD besides I’m using it 2 years, so I got used to it.