DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’» is a community of 970,177 amazing developers

We're a place where coders share, stay up-to-date and grow their careers.

Create account Log in
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 πŸ—¨.

Top 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 Author

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 πŸ˜‚πŸ˜‚

This post blew up on DEV in 2020:

js visualized

πŸš€βš™οΈ JavaScript Visualized: the JavaScript Engine

As JavaScript devs, we usually don't have to deal with compilers ourselves. However, it's definitely good to know the basics of the JavaScript engine and see how it handles our human-friendly JS code, and turns it into something machines understand! πŸ₯³

Happy coding!