How to Use Vue Router: A Complete Tutorial

Written by Shadid Haque

One of the most powerful features of modern single-page web applications (SPA) is routing. Modern single-page apps such as a Vue application can transition from page to page on the client-side (without requesting the server). Vue Router is the official library for page navigation in Vue applications. Vue Router is simple to use, yet powerful. In this article, we will deep dive into Vue Router 4 (used with Vue 3). We will go over everything you need to know to use Vue Router comfortably.

We will cover:

  • Vue Router Fundamentals
  • Dynamic routing
  • How to pass router params
  • Lazy loading

Whether you are a beginner just getting into Vue Router or a seasoned JavaScript/Vue developer looking to skill up, there’s something for you in this tutorial. Let’s get started.

👉 We have also created a completely free in-depth Vue Router video course. If you learn better by watching videos, we highly recommend you give it a shot. Click here to watch the Vue Router course.

Vue Router Fundamentals

Let’s create a new project and get right into coding. We’ll create a new project with vue-cli. If you don’t have it installed you can install it by running npm install -g @vue/cli.

# Create a new Vue project
vue create myapp
cd myapp
# start your app by running the following command
npm run serve

Next we can add the Vue Router to our project by running the following command.

vue add router

The cli will ask if we want history mode. For this tutorial we’ll be using history mode, so we’ll select yes.

Let’s take a look at the folder structure that was created for us.

Vue router folder structure

A folder named views is created for us along with two files About.vue and Home.vue. These files represent our pages. A file named router/index.js file is also generated. This file contains all the router configurations. Let’s open up the router/index.js file.

import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'
const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/about',
    name: 'About',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
  }
]
const router = createRouter({
  history: createWebHistory(process.env.BASE_URL),
  routes
})
export default router

We are importing createRouter and createWebHistory from the vue-router library. Next, we import the Home component from views/Home.vue. On line 3 we are declaring an array of objects named routes. This array represents our routes in the application. These array items are called route objects. The first route object has a path / which means this is going to be our base URL. The component property represents what component will be rendered when the user visits this path. We will render the Home page on this path. Finally, the name property represents the name of the route.

We are pretty much following the same logic for the /about the path. However, instead of directly importing the component we are importing it through Webpack’s code splitting feature. More on this later.

Now let’s jump into App.vue file.

<template>
  <div id="nav">
    <router-link to="/">Home</router-link> |
    <router-link to="/about">About</router-link>
  </div>
  <router-view/>
</template>
<style>
</style>  

Observe the router-link tags. These tags are just fancy anchor links. However unlike an anchor link (<a href=""> tag) the <router-link> will not reload the whole page. Remember Vue is a single-page application. The data for the app is already downloaded from the server. When we route to another view the application just hides some information and displays the requested information. router-link tags have a to property which refers to which page to visit. The <router-view/> tag is what renders the right component when navigation links are triggered.

Let’s add our own route to this application.

// App.vue
<template>
  <div id="nav">
    <router-link to="/">Home</router-link> |
    <router-link to="/about">About</router-link>
    <router-link to="/profile">Profile</router-link>
  </div>
  <router-view/>
</template>

We need to add a new router-link to App.vue. Next we create a new component in the views directory.

    // views/Profile.vue
    <template>
      <div class="home">
        Profile Info
      </div>
    </template>

Finally, in our routes array we have to import this and specify the route path.

    import { createRouter, createWebHistory } from 'vue-router'
    import Home from '../views/Home.vue'
    import Profile from '../views/Profile.vue'
    const routes = [
      {
        path: '/',
        name: 'Home',
        component: Home
      },
      {
        path: '/profile',
        name: 'profile',
        component: Profile,
      },
      {
        path: '/about',
        name: 'About',
        // route level code-splitting
        // this generates a separate chunk (about.[hash].js) for this route
        // which is lazy-loaded when the route is visited.
        component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
      }
    ]
    const router = createRouter({
      history: createWebHistory(process.env.BASE_URL),
      routes
    })
    export default router

That’s it we have our own routes added to the application.

vue router

How to use router params with Vue Router

First of all, let’s take a look at what router parameters (router params in short) are and why they are important. Let’s say we have a page in our application where we show users a list of all the blog posts available.

vue router params example

Let’s say in our application this path is /posts. When a user clicks on any of these articles the user is taken to that article page. For each article the path will be different (/posts/article-1, /posts/article-2, etc.). How do we achieve this? We can add a new route for every post we have, but then we have to change our code every time a new post is published. Therefore, we will use a dynamic route. This is where router params comes in handy.

In our application, we can specify a generic route like the /posts and, then we can specify optional route params to the same route like this /posts/:id. The :id picks up any dynamic string as a parameter. This means we can now route to paths like /posts/article-1 , /posts/article-2, etc. and the Vue router in the application will know which path we are trying to go to.

Learn Vue.js 3 With Vue School

Let’s see this in action inside our application.

// App.vue
<template>
  <div id="nav">
    <router-link to="/">Home</router-link> |
    <router-link to="/about">About</router-link> |
    <router-link :to="{ name: 'profile', params: { username: 'mark2021' } }" >
      Profile
    </router-link>
  </div>
  <router-view/>
</template>

In our router-link tag we can use the :to property to pass in an object with name and params data. The params object can be any type of data (i.e. strings, numbers, objects). In the code snippet above we are passing in an object with username with a string value (mark2021).

How to access route params from the view

When we add Vue router to our Vue application we get access to a special $route object inside the global scope of our application. This object holds all the router information of our application. We can access $route object by simply calling this.$route. The params information is also available within this $route object. We can access the params object inside of the Profile component through the $route object. Take a look at the code snippet below.

    <template>
      <div class="profile">
        Profile Info
      </div>
      <span>
          {{ this.$route.params.username }}
      </span>
    </template> 

Dynamic Routing

Below is a quick reference table to help you visualize how dynamic routes work.

route pattern URL path $this.route.params
/product/:name /product/apple-watch { name: "apple-watch"}
/product/:name/comment/:comment_id /product/apple-watch/comment/123 { name: 'apple-watch', comment_id: '123' }

In the previous section we saw how, we can pass in additional information with <router-link>. Dynamic routes are a similar concept. In this scenario the parameter is a part of the URL itself.

Let’s take a look how we can define dynamic routes in our application. Let’s create a new component under view and call it Product.

    <template>
      <div>
        Product Page
      </div>
      <span>
          Looking for Product: {{ this.$route.params.id }}
      </span>
    </template>

Now we can add this component to our routes.

    const routes = [
      // rest of the code ...
      { path: '/product/:id', component: Product },
    ]

Notice we appended a dynamic parameter to :id to the URL. Now if you visit http://localhost:8080/product/12343 in our browser you can see that the component will have access to the dynamic parameter that was passed through the URL.

We could then use this Id to fetch the actual product from our API in a lifecycle hook.

dynamic routing with vue router

We can also have multiple dynamic parameters in our URL. The dynamic segments will map to corresponding fields of $route.params.

Let’s take a look at how it works. we will first make some quick changes in our product route.

    const routes = [
      // rest of the code ...
       { path: '/product/:id/:category', component: () => import('../views/Product.vue') }
    ]

Instead of one param :id, now we are specifying two params. Now let’s go the path http://localhost:8080/product/12343/electronics and open up the Vue devtools. As you can see from the screenshot below we have now access to params and these params are mapping to specified variable name id and category.

Lazy loading

Let’s talk about lazy loading. This is one of the advanced features that Vue Router provides out of the box. Let’s open up our devtools and observe the js tab.

You can see that when we load the application for the first time it loads an app.js script. When you navigate to /profile route or /product route you can see no new javascript is being loaded. This is because all the JavaScript code for those components was already loaded with app.js. In a smaller application, this is not a problem. However, what if we have a large application. In that case, loading all the JS code in one go can make the page load time significantly longer. Lazy loading is used to avoid this.

When we lazy load, we load only the parts we need, when we need them.

    // router/index.js
    const routes = [
      {
        path: '/',
        name: 'Home',
        component: Home
      },
      {
        path: '/profile',
        name: 'profile',
        component: Profile,
      },
      { path: '/product/:id', component: Product },
      {
        path: '/about',
        name: 'About',
        component: () => import('../views/About.vue')
      }
    ] 

Take a look at line 17 of router/index.js. Do you recall this from an earlier example? The About component here is being imported with an arrow function. This is an example of lazy loading. Unlike Home, Profile and Product component the About component is not loaded with the app.js. The About component will only get loaded when a user visits the /about route. This is all we have to do to implement lazy load. This lazy loading is being done through Webpack’s code splitting feature. Under the hood Vue uses Webpack as a bundler. You can learn more about advanced Vue features such as code splitting, Webpack configuration etc. in depth in our Vue 3 Masterclass course.

We can update our code to use lazy loading for each route.

    import { createRouter, createWebHistory } from 'vue-router'
    import Home from '../views/Home.vue'
    const routes = [
      {
        path: '/',
        name: 'Home',
        component: Home
      },
      {
        path: '/profile',
        name: 'profile',
        component: () => import('../views/Profile.vue')
      },
      { path: '/product/:id', component: () => import('../views/Product.vue') },
      {
        path: '/about',
        name: 'About',
        component: () => import('../views/About.vue')
      }
    ]
    const router = createRouter({
      history: createWebHistory(process.env.BASE_URL),
      routes
    })
    export default router

💡 If you are looking to distinguish yourself as a developer with a deep understanding of Vue then give our Vue 3 Masterclass a shot. In this course, we delve deep into some of the advanced features of Vue such as higher-order functions, code splitting, Webpack configuration, creating vue plugins, route guards and much more.

Programmatic Navigation

In our applications, there will be scenarios when we would want to programmatically navigate to another page. Inside our application, we have access to the router instance as $router . We can access it by calling **this.$router**. The router instance has a function called push. This function can be used to navigate to different routes. Here are some examples of how it works

    // route by route path
    this.$router.push('home')

    // object
    this.$router.push({ path: 'home' })

    // named route navigation with parameters
    this.$router.push({ name: 'user', params: { userId: '123' } })

    // with query params, resulting in /profile?info=some-info
    this.$router.push({ path: 'profile', query: { info: 'some-info' } })

Where to go from here

I hope this article gave you an overview of the different functionalities of Vue Router. We discussed the most important and commonly used features of Vue Router. Feel free to visit the vue router documentation for more in-depth details about the various APIs. Here at VueSchool we have created a completely free course on Vue Router. For more in-depth Vue learning material you can also take a look at our Vue 3 Masterclass course.

We also have a Vue Router 3 For Everyone course for Vue.js 2.

That’s all for today, happy hacking.

Learn Vue.js 3 With Vue School

Leave a Reply

Your email address will not be published. Required fields are marked *

Up Next:

Vuex, the Official Vue.js Store

Vuex, the Official Vue.js Store