How to create a global snackbar using Nuxt, Vuetify and Vuex.
Tags: vue, nuxt, vuetify, javascript
Published: 2019-10-10 12:17:01

### TL;DR
<a href="https://github.com/stephannv/global-vuetify-snackbar/commit/e3a0593b0fa1eaa3d10738815828636932c476f9" target="_blank">Code here</a>

### 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](https://vuetifyjs.com)'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](https://quasar.dev) 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](https://nuxtjs.org) 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](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](https://nuxtjs.org/guide/vuex-store).
```javascript
// ~/store/snackbar.js

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

export const mutations = {
  showMessage (state, payload) {
    state.content = payload.content
    state.color = payload.color
  }
}
```

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.

```javascript
// ~/plugins/notifier.js

export default ({ app, store }, inject) => {
  inject('notifier', {
    showMessage ({ content = '', color = '' }) {
      store.commit('snackbar/showMessage', { content, color })
    }
  })
}
```
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](https://nuxtjs.org/guide/plugins).

We also need to register the plugin on `nuxt.config.js`
```javascript
export default {
  ...
  plugins: [
    '~/plugins/notifier.js'
  ],
  ...
}
```

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

```vue
// ~/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>
```
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:

```vue
// ~/layouts/default.vue

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

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

export default {
  components: { Snackbar },
  ...
}
</script>
```

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

```vue
// ~/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>
```

### 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.