Home / Blog / Composing Layouts with Vue Router
Composing Layouts with Vue Router

Composing Layouts with Vue Router

Daniel Kelly
Daniel Kelly
February 28th 2022

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.

about page screenshot with left and right sidebars

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.

blog post with sidebar on right

PostShow.vue

While still other pages, require no sidebar at all.

home page screenshot

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.

Vue Router Named Views

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>*
about page with right and left sidebars

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.

Sidebar 2 added to PostShow.vue

blog post with sidebar on right

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

Sidebar 1 on left hand side of PostShow.vue

blog post with sidebar on left

//router/index.js
{
    path: '/posts/:id',
    components: {
        default: () => import('@/pages/PostShow.vue'),
        LeftSidebar: () => import('@/components/SidebarOne.vue'),
},

Sidebar 1 on right hand side of PostIndex.vue

post listings page with sidebar on right

//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... 🤔).

AboutShow.vue on right hand side of PostShow.vue

about page on right hand side of blog post page

{
  path: '/posts/:id',
  components: {
    default: () => import('@/pages/PostShow.vue'),
    RightSidebar: () => import('@/pages/AboutShow.vue'),
  },
},

Conclusion

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.

Start learning Vue.js for free

Daniel Kelly
Daniel Kelly
Daniel is the lead instructor at Vue School and enjoys helping other developers reach their full potential. He has 10+ years of developer experience using technologies including Vue.js, Nuxt.js, and Laravel.

Comments

Latest Vue School Articles

How to Access Vue Refs Defined in Script Setup within Unit Tests

How to Access Vue Refs Defined in Script Setup within Unit Tests

Need to access a component’s data defined within script setup? In this article we’ll teach you how! But be warned you probably want to approach your test a little differently.
Daniel Kelly
Daniel Kelly
48 Hours of Unlimited Vue.js Learning: Your Guide to Vue School&#8217;s Free Weekend

48 Hours of Unlimited Vue.js Learning: Your Guide to Vue School’s Free Weekend

Vue School’s Free Weekend is coming! For 48 hours, you’ll get free access to over 1300 lessons across 65 expert courses. Whether you’re a beginner or advanced, this is your chance to explore new Vue.js topics.
Maria Panagiotidou
Maria Panagiotidou

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!

Follow us on Social

© All rights reserved. Made with ❤️ by BitterBrains, Inc.