Vuex Powered Sidebar with NuxtJs
NuxtJs is an awesome framework that takes practical and common structural patterns and creates a highly manageable boilerplate for your VueJS project. I'm personally just getting started with Nuxt, but so far I'm seriously impressed. There's always this routine when starting a new Vue project that Nuxt helps alleviate while also applying some tried-and-true best practices to your project free of charge.
Obviously this makes Nuxt opinionated, for good reason, but that always comes with a bit of a learning curve. In this article I'll walk you through creating a navigation sidebar that's able to be toggled from anywhere in your app through the magic of state.
Starting your Nuxt project
First things first, we'll need to setup our project. You can use a handy script using npx or yarn (dealer's choice).
npx
npx create-nuxt-app <project-name>
yarn
yarn create-nuxt-app <project-name>
You'll be asked a series of questions about your project. If you're unsure how to answer any of these, just go with the defaults! Once you get through that interrogation, you should have a stylish folder structure set for you. Go ahead and start up your dev server and get started.
npm run dev
You should see your test page and be ready to get started!
Build the components
Now I've already been busy, so I have an existing project I'm going to work with. I'll do my best to keep this as arbitrary as possible so you can follow along, but if you have any questions feel free to leave a comment (or DM me on Twitter, I'm always happy to help).
I have 2 relevant components here:
- NavBar.vue
- SideBar.vue
Seems redundant aye? Its mainly for layout purposes. The NavBar features the cliche hamburger button which opens my SideBar. You can set this up however you'd like so long as you've got a sidebar, and a button somewhere that summons it.
Here's a glimpse of what I'm working with.
NavBar Template
<template>
<!-- Top Navbar -->
<nav
class="top-navbar flex flex-row align-center p-2 fixed w-full"
style="z-index: 9001;"
>
<!-- Logo Brand -->
<div class="flex-grow">
<router-link :to="{ name: 'HomeView' }">
<img alt="ImStallion Logo" :src="logoIcon" class="w-16 ml-3" />
</router-link>
</div>
<!-- /Logo Brand -->
<!-- Menu Button -->
<button class="p-4" @click="toggle">
<font-awesome-icon :icon="['fas', 'bars']" size="lg"></font-awesome-icon>
</button>
</nav>
<!-- /Top Navbar -->
</template>
SideBar Template
<template>
<!-- Top Navbar -->
<nav
class="top-navbar flex flex-row align-center p-2 fixed w-full"
style="z-index: 9001;"
>
<!-- Logo Brand -->
<div class="flex-grow">
<router-link :to="{ name: 'HomeView' }">
<img alt="ImStallion Logo" :src="logoIcon" class="w-16 ml-3" />
</router-link>
</div>
<!-- /Logo Brand -->
<!-- Menu Button -->
<button class="p-4" @click="toggle">
<font-awesome-icon :icon="['fas', 'bars']" size="lg"></font-awesome-icon>
</button>
</nav>
<!-- /Top Navbar -->
</template>
You'll see on both of these templates we have a @click
directive referencing a method called toggle
. This will come from a Vuex mapped mutation.
Vuex and Nuxt
Nuxt uses a namespaced modules approach with Vuex meaning you'll have individual js files which represent state. For this example, it'll be drawer.js
.
NOTE: Nuxt doesn't know you want to use Vuex until you tell it. The way you tell it is by creating a file in the store directory. This may not take affect immediately, so after creating a file, restart your dev server to be safe.
In /store
create a file called drawer.js
and provide the following contents to get started.
export const state = () => ({
drawer: false
});
This gives us an initial value to start off with, but we'll want to be able to toggle this obviously, so in that same file we'll create a mutation
as well called toggle.
export const mutations = {
toggle(state) {
state.drawer = !state.drawer;
}
};
Lastly, we need to be able to get the value at any time which we'll do with a getter
.
export const getters = {
getDrawerState(state) {
return state.drawer;
}
};
Once you have all of these in your drawer.js
module, you'll effectively be able to use your navigation drawer from any component!
Using your mutation & getter to toggle the sidebar
You'll have 1 component where you'll need your getter
, in the SideBar component to bind to the v-if
directive so your Vue app knows when the SideBar should be rendered.
You'll have 2 components where you'll need your mutation
, in the NavBar component for opening the SideBar, and in the SideBar to close the SideBar.
First lets make sure your SideBar knows when its allowed to come out. In your SideBar component just after your <script>
opening tag, import mapGetters
& mapMutations
from vuex
.
import { mapGetters, mapMutations } from 'vuex';
Next we'll want to map our getter
as a computed property called drawer
which when evaluated as true
, shows our sidebar. As well, we can map our toggle mutation
to a method to bind to our close button.
export default {
methods: {
...mapMutations({ toggle: "drawer/toggle" })
},
computed: {
...mapGetters({ drawer: "drawer/getDrawerState" })
}
};
Same as above in our NavBar we'll map our toggle mutation
to use in our hamburger button so we can open the SideBar and you're all set!
Conclusion
That's pretty much it. We've seen a bit about how Nuxt structures our Vue application, how namespaced modules work with Nuxt & Vuex, and how we can use mapGetters
& mapMutations
to handle basic functionality like toggling a sidebar from any component!
Top comments (4)
Nice! Definitely a big fan of Vue and Nuxt and would love to see more packages and plugins using these.
The SideBar template is the same as the NavBar template.
@codespent the example code for the SideBar template is just a repeat of the NavBar code.
I don't know why this didn't work for me, copied everything and made changes where necessary