How to create a global snackbar using Nuxt, Vuetify and Vuex.
Stephann

Stephann @stephann

About: Software Engineer. My favorite tools: Ruby, Rails, Vue.js, Godot, Lua.

Location:
Fortaleza, Brasil
Joined:
Aug 27, 2019

How to create a global snackbar using Nuxt, Vuetify and Vuex.

Publish Date: Oct 10 '19
64 23

TL;DR

Code here

Intro

Snackbars, also known as alerts or toasts, are present in every application. They are handy to show important information after an user interaction. If you are using Vuetify's snackbar component, you might have realized there isn't a global object to call a function and show your snackbar component. I have used Quasar for a short time and I fell in love with this.$q.notify('Message'), so I tried to replicate the behavior with Vuetify and Vuex, and I will share here how I did it. For this tutorial, I'll be using Nuxt but you can adapt the code for vanilla Vue applications as well (kudos to David for showing how to implement the snackbar without Nuxt: https://dev.to/dzvid/comment/17nip).

Store

First we need to create a store module for our snackbar. If you don't know Vuex, think the store as a global repository for our variables. More information about Nuxt and Vuex can be found here.

// ~/store/snackbar.js

export const state = () => ({
  content: '',
  color: ''
})

export const mutations = {
  showMessage (state, payload) {
    state.content = payload.content
    state.color = payload.color
  }
}
Enter fullscreen mode Exit fullscreen mode

Our store will have the content and the color states. This data will be used to fill our snackbar component.

It isn't a good practice to modify state data directly, so we created a mutation named showMessage. It will change the state values and make it easier to listen for changes.

Plugin

In order to have the notifier function available across the application, we need to create a plugin. We could to skip creating this plugin and just use this.$store.commit(...) or use mapMutation(...) on our components, but this.$notifier.showMessage(...) is more legible and it avoids to map mutations to multiple components.

// ~/plugins/notifier.js

export default ({ app, store }, inject) => {
  inject('notifier', {
    showMessage ({ content = '', color = '' }) {
      store.commit('snackbar/showMessage', { content, color })
    }
  })
}
Enter fullscreen mode Exit fullscreen mode

This code injects a $notifier across our components. This object has the showMessage function that receives content and color and commits showMessage mutation to our snackbar store. For more information about Nuxt plugins, you can check here.

We also need to register the plugin on nuxt.config.js

export default {
  ...
  plugins: [
    '~/plugins/notifier.js'
  ],
  ...
}
Enter fullscreen mode Exit fullscreen mode

Snackbar component

Our snackbar component will be simple. It will be responsible for showing the message on screen.

// ~/components/Snackbar.vue

<template>
  <v-snackbar v-model="show" :color="color">
    {{ message }}
    <v-btn text @click="show = false">Close</v-btn>
  </v-snackbar>
</template>

<script>
export default {
  data () {
    return {
      show: false,
      message: '',
      color: ''
    }
  },

  created () {
    this.$store.subscribe((mutation, state) => {
      if (mutation.type === 'snackbar/showMessage') {
        this.message = state.snackbar.content
        this.color = state.snackbar.color
        this.show = true
      }
    })
  }
}
</script>
Enter fullscreen mode Exit fullscreen mode

When the component is created it starts to listen for the mutation. It will set snackbar information and show it when the mutation showMessage from our snackbar store is called.

Layout

We have to add our snackbar to our application:

// ~/layouts/default.vue

<template>
  <v-app>
    ...
    <Snackbar></Snackbar>
    ...
  </v-app>
</template>

<script>
import Snackbar from '~/components/Snackbar.vue'

export default {
  components: { Snackbar },
  ...
}
</script>
Enter fullscreen mode Exit fullscreen mode

Showing the snackbar

Finally, we will create a button to show that our snackbar is working:

// ~/pages/index.vue

<template>
  ...
  <v-btn color="primary" @click="showSnackbar">
    Show snackbar
  </v-btn>
  ...
</template>

<script>
export default {
  ...
  methods: {
    showSnackbar () {
      this.$notifier.showMessage({ content: 'Hello, snackbar', color: 'info' })
    }
  }
  ...
}
</script>
Enter fullscreen mode Exit fullscreen mode

Conclusion

That's it. That was easy. You will be able to call this.$notifier.showMessage(...) from everywhere without having to create a snackbar for each situation. What you could do next is allowing it to show multiples snackbars at once and add custom actions to snackbar beyond the close button. But that's all folks, if you find a better way to solve this problem, please, don't hesitate to comment.

Comments 23 total

  • Md Abu Taher
    Md Abu TaherOct 11, 2019

    This is great!

    Interesting way to show code with link to specific commit. It shows exactly what changed in case anyone wants to compare it with this tutorial.

    One thing I instantly thought upon seeing this, "what? all those libraries just to show a snackbar?" :D Who knew the web development would become so broad!

    • Stephann
      StephannOct 11, 2019

      Yeah, front end development can be complex sometimes haha.

  • Jeff Bluemel
    Jeff BluemelFeb 5, 2020

    Fantastic, works perfect and was well explained.

  • Akshay Anand
    Akshay AnandFeb 10, 2020

    Amazing post !!

    I was just wondering as to how we can do this without using nuxt and just plain vuejs

    • Chandher Shekar
      Chandher ShekarSep 30, 2020

      Did you happen to figure out how to do this?

      • Akshay Anand
        Akshay AnandOct 1, 2020

        Since nuxt was not a requirement for me. I ended up implementing it using plain vuejs and vuex

  • UZU, J
    UZU, JApr 16, 2020

    i am using nuxt. still getting this.
    Uncaught (in promise) TypeError: Cannot read property '$notifier' of undefined

  • Mohammad Reza Ghazy
    Mohammad Reza GhazyApr 23, 2020

    excellent job Stephann ! important step to code reuse ! also it is possible to use this method for confirmation dialog.. which always you have to ask when you want to delete an item..
    on the other hand we have three file creation and two file update for just a "snack-bar" message !
    we can also use third-party library like sweetalert2. they did good job !

  • Sujith D
    Sujith DJun 17, 2020

    This is what exactly I was looking for, great explained 😍😍

  • Chi89
    Chi89Jun 18, 2020

    Thanks a lot.

    This is precisely what I'm looking for.

  • Daniel
    DanielJul 25, 2020

    man I love you

  • juli4g33k
    juli4g33kJul 27, 2020

    This was the first more complex task I had to implement for one of my previous employers and which I failed miserably, precisely because I went for the naive approach to create a component and import it in every other component where I needed to spawn a snackbar. I ended polluting the entire codebase with snippets of code for the snackbar.

    Thanks for sharing your approach, it's easier and more elegant.

  • Raju Ahmed
    Raju AhmedSep 17, 2020

    thank you. it's a great tutorial. I having trouble the colour doesn't work.

  • Pratik Rane
    Pratik RaneSep 25, 2020

    Perfect! This is exactly what I was looking for. I liked how quasar gave this out of the box, it's a handy feature to have.

  • David
    DavidNov 10, 2020

    For those using vue and dont have Nuxt inject:

    1 - Create a snackbar plugin receiving vuex store as option:

    // src/plugins/snackbar.js
    const snackbarPlugin = {
      install: (Vue, { store }) => {
        if (!store) {
          throw new Error('Please provide vuex store.');
        }
    
        Vue.prototype.$snackbar = {
          showMessage: function ({
            content = '',
            color = ''
          }) {
            store.commit(
              'snackbar/showMessage',
              { content, color },
              { root: true }
            );
          }
        };
      },
    };
    export default snackbarPlugin;
    
    Enter fullscreen mode Exit fullscreen mode

    2 - At your main.js, pass your plugin to Vue:

    // src/main.js
    import Vue from 'vue';
    import App from './App.vue';
    import router from './router';
    import store from './store';
    import snackbarPlugin from './plugins/snackbar';
    
    Vue.use(snackbarPlugin, { store })
    
    Vue.config.productionTip = false;
    
    new Vue({
      router,
      store,
      render: (h) => h(App),
    }).$mount('#app');
    
    Enter fullscreen mode Exit fullscreen mode
    • Stephann
      StephannJan 21, 2021

      Thanks for this. I added link for this comment on post for other people who doesn't use Nuxt.

  • Andrés Carrillo
    Andrés CarrilloNov 11, 2020

    Thank you so much!!!

  • Artu
    ArtuDec 24, 2020

    Great instruction, the ready to use functionality

  • Fiyinfoluwa Akinsiku
    Fiyinfoluwa AkinsikuFeb 10, 2021

    This was really helpful, thanks!

    Also if anyone is getting this error Property '$notifier' does not exist on type 'CombinedVueInstance<Vue..., a workaround is to use this ( this as any ).$notifier.showMessage(...) instead.

  • Japanesen
    JapanesenMar 1, 2021

    I'm having issues with the :app setting, no matter what I do it doesn't respect my footer / header etc. and just goes on top of them. :app="true" or :app="false", none of it works. Any ideas why? (Nuxt + vuetify)

  • Saeed Hassani Borzadaran
    Saeed Hassani BorzadaranApr 5, 2021

    Thanks Stephann :)

  • vishnu p manoharan
    vishnu p manoharanFeb 8, 2023

    I Set up this notifier, and it's working on the components and page, but while I try to trigger $notifier from a another plugin, the snack bar didn't shown!

    • Stephann
      StephannFeb 28, 2023

      You will have to search about how inject a plugin in another plugin. I'm not using Nuxt anymore, so I don't know how to solve this problem.

Add comment