Vue Router is the de facto standard for creating routes in Vue.js SPA’s. Did you know though, that besides using it to map routes to page components, you can also use it to compose page layouts? That’s an interesting proposal. Let’s see how it’s done.
Let’s say we’re building a blog where there’s the potential for some pages to have a sidebar on each side of the main content.
AboutShow.vue
Other pages only require one of the sidebars alongside the content and the position before or after the main content could be variable.
PostShow.vue
While still other pages, require no sidebar at all.
Home.vue
How can we accomplish this? Option 1 would be to create components for the sidebars and include them in each page as needed. For example AboutShow.vue
would get a route record that looks like this:
// router/index.js
{
path: '/about',
component: () => import('../pages/AboutShow.vue')
},
And a corresponding Page component something like this:
// *AboutShow.vue
<template>
<div class="flex ...">
<SidebarOne />
<main>....</main>
<SidebarTwo />
</div>
</template>
<script setup>
import SidebarOne from "@/components/SidebarOne"
import SidebarTwo from "@/components/SidebarTwo"
</script>*
However this means, the about page will always be coupled to the sidebars. In most cases this is probably no big deal. However, let’s examine an alternate approach where the layout is composed not at the page level but at the router level.
To accomplish this we’ll provide a components
(plural) option instead of a component
(singluar) option to the route record.
{
path: '/about',
components: {
default: () => import('@/pages/AboutShow.vue'),
LeftSidebar: () => import('@/components/SidebarOne.vue'),
RightSidebar: () => import('@/components/SidebarTwo.vue'),
},
},
Here we’ve defined that the about route should include a default component, that is the about page. This is what will show up in the RouterView component like you’re used to seeing. However, it should also include a LeftSidebar
component which is mapped to SidebarOne
and a RightSidebar
component which is mapped to SidebarTwo
.
Now in order for the LeftSidebar
and RightSidebar
components to know where to show up, we must use additional router views, called named views, alongside our default router view. We can also wrap the router views in a div with some tailwind classes to lay things out nicely.
<!-- App.vue -->
<template>
<!--...-->
<div class="sm:flex container p-5 mx-auto content justify-betweenflex-wrap">
<RouterView class="view main-content w-full order-2"></RouterView>
<RouterView name="LeftSidebar" class="view order-1 w-full"></RouterView>
<RouterView name="RightSidebar" class="view order-3 w-full"></RouterView>
</div>
<!--...-->
</template>
Notice the new router views have name attributes that match up with the keys we provided to the components property of the route record (LeftSidebar
and RightSidebar
).
Finally, this time the page itself can exclude the sidebars all together and the result is the same.
// *AboutShow.vue
<template>
<div>
<main>....</main>
</div>
</template>*
This might seem a little round about, but the cool thing now is that, with these additional named views in place, we can flexibly add one or both of the sidebars on any new route record.
{
path: '/posts/:id',
components: {
default: () => import('@/pages/PostShow.vue'),
RightSidebar: () => import('@/components/SidebarTwo.vue'),
},
},
Furthermore we can do it in any order we desire. That is SidebarOne
could be on the left of one page and right of the other, etc.
//router/index.js
{
path: '/posts/:id',
components: {
default: () => import('@/pages/PostShow.vue'),
LeftSidebar: () => import('@/components/SidebarOne.vue'),
},
//router/index.js
{
path: '/posts/',
components: {
default: () => import('@/pages/PostIndex.vue'),
RightSidebar: () => import('@/components/SidebarOne.vue'),
},
Or we could map wholly different components to left or right sidebars for an infinite number of sidebar possibilities (hmmm...even other page components... 🤔).
{
path: '/posts/:id',
components: {
default: () => import('@/pages/PostShow.vue'),
RightSidebar: () => import('@/pages/AboutShow.vue'),
},
},
After seeing named routes in action, you may be thinking: “How can I utilize named routes in my next project?” Of course, the sidebar use case seems pretty legit, but it’s not limited to just that.
To be honest, it’s not an approach I’ve ever taken but that’s only because it’s new to me. That means, I can’t really break down the pros and cons, so much as show you it exists and let you come up with the strategy on when to use it.
If you’d like to play with named routes some more, feel free to fork this Stackblitz sandbox (the source of the screenshots throughout the post) and see what you can come up with. I’d love to see your thoughts in the comments below, both if you’ve used this approach before or if you’re just learning about it like me.
Also, if you’d like to checkout the spec for named routes yourself, you can find that in the docs.
Lastly, if you’re looking to get even more insight into using Vue Router with your Vue.js applications, checkout our course Vue Router 4 for Everyone. During the course we use Vue Router to build a simple example travel application and dive into both the basics of Vue Router as well as it’s more advanced features.
Our goal is to be the number one source of Vue.js knowledge for all skill levels. We offer the knowledge of our industry leaders through awesome video courses for a ridiculously low price.
More than 200.000 users have already joined us. You are welcome too!
© All rights reserved. Made with ❤️ by BitterBrains, Inc.