DEV Community

Cover image for Create a Simple 0-dependency Toast (part 2) - Class-based
tsanak
tsanak

Posted on

Create a Simple 0-dependency Toast (part 2) - Class-based

Intro

Please read the first of this two part mini-series to get a better understanding of this post 🙂.

A few minutes after I published the first post on how to create a simple Toast, I started thinking about ways to make it better and easier to use.

After some thinking, I decided that the best way to easily manage and create Toasts is through classes. So I created a class-based Toast, that accepts a few options to customize the functionality.

These options are the following:

  1. title: (string) What the toast will "say" [default: '']
  2. timer: (int) How long before the Toast auto expires in ms [default: 2000]
  3. alwaysOn: (boolean) Overrides the timer option and the Toast doesn't auto expire [default: false]
  4. dismiss: (boolean) Shows an 'x' icon, when user clicks the icon => the Toast closes [default: false]

How it works

First the styles are the following:

.toast {
  position: fixed;
  bottom: -100px;
  left: 50%;
  transform: translateX(-50%);
  width: 100%;
  max-width: 300px;
  background-color: #213cfd;
  background-image: linear-gradient(19deg, #213cfd 0%, #b421ff 100%);
  color: #fff;
  font-size: 16px;
  padding: 10px;
  -webkit-transition: bottom 350ms;
  -moz-transition: bottom 350ms;
  -o-transition: bottom 350ms;
  -ms-transition: bottom 350ms;
  transition: bottom 350ms;
}

.toast.active {
  bottom: 20px;
}

.toast--dismiss {
    border: 0;
    outline: 0;
    background: transparent;
    color: #fff;
    position: absolute;
    top: 1px;
    right: 1px;
    font-size: 12px;
    cursor: pointer;
}

You can customize the css to fit your needs: change the background color of the Toast, the position etc.

The javascript class:

class Toast {
    constructor(title = '', {
        timer = 2000,
        alwaysOn = false,
        dismiss = false
      } = {}) {
        this.autoTimer = null;
        let self = this;
        /* Close all previous Toasts */
        document.querySelectorAll('.toast').forEach(el => {
            el.classList.remove('active');
        })
        this.title = title;
        /* Check if timer is valid integer */
        let ms = parseInt(timer);
        if(isNaN(ms) || ms < 1) {
            ms = 2000;
        }
        this.toast_el = document.createElement('div');
        this.toast_el.classList.add('toast');
        this.toast_el.innerText = title;

        if(dismiss) {
            let toast_dismiss = document.createElement('button');
            toast_dismiss.setAttribute('type', 'button');
            toast_dismiss.classList.add('toast--dismiss');
            toast_dismiss.innerHTML = "&#10006;";

            this.toast_el.appendChild(toast_dismiss);

            toast_dismiss.addEventListener('click', () => {
                /* Remove Toast when user click on 'x' button */
                self.toast_el.classList.remove('active');
                setTimeout(function() {
                    document.querySelector('body').removeChild(self.toast_el);
                }, 100);
                clearTimeout(self.autoTimer);
            });
        }
        /* Append Toast element to body */
        document.querySelector('body').appendChild(this.toast_el);
        setTimeout(function() {
            self.toast_el.classList.add('active');
        }, 100);

        if(!alwaysOn) {
            /* Auto expire the Toast after the specified ms */
            this.autoTimer = setTimeout(function() {
                self.toast_el.classList.remove('active');

                setTimeout(function() {
                    document.querySelector('body').removeChild(self.toast_el);
                }, 100);
            }, ms);
        }
    }
}

Examples

1. Classic Toast

document.querySelector('#btn-show-toast').addEventListener('click', (e) => {
    let toast = new Toast("✔️ This is a classic toast! 👏", {
        timer: 2000
    });
});

Alt Text

2. Dismissable Toast with timer

document.querySelector('#btn-show-toast--dismiss').addEventListener('click', (e) => {
    let toast = new Toast("✔️ This is a dismissable toast with auto expire! 👏", {
        timer: 2000,
        dismiss: true
    });
});

Alt Text

3. Always-on, dismissable Toast

document.querySelector('#btn-show-toast--dismiss--no-timer').addEventListener('click', (e) => {
    let toast = new Toast("✔️ This is a dismissable toast without timer! 👏", {
        dismiss: true,
        alwaysOn: true
    });
});

Alt Text

Demo with all the code

Outro

🎉 Thank you for reading through all the post! 🎉

If you have any questions or feedback, let me know in the comments 🗨.

Oldest comments (2)

Collapse
 
js2me profile image
Sergey S. Volkov

Thanks, will add this to my site, but add a small integration with React :)

Collapse
 
tsanak profile image
tsanak

Thank you for your comment!

I tried for like an hour to convert this to a React component, but the problem is that I don't know React 😅 !
Then I tried to think at it from a Vue standpoint and I realized that while it is very feasible, it would take away the fun of just writing:

new Toast("✔️ This is a dismissable toast without timer! 👏", {
    dismiss: true,
    alwaysOn: true
});

You can find the hackiest solution to use the Toast Class in React in the codepen below:

please don't judge me on that code 😂😂