Skip to main content
Vue.js for Beginners to Advanced
CHAPTER 14 Beginner

Vue Router Basics

Updated: May 18, 2026
5 min read

# CHAPTER 14

Vue Router Basics

1. Chapter Introduction

Vue Router is the official client-side routing library for Vue. It enables Single Page Application (SPA) navigation — clicking links changes the URL and renders different components WITHOUT page reloads. This is what makes Vue apps feel instant.

2. Learning Objectives

  • Set up Vue Router in a Vue 3 project.
  • Define routes and map them to components.
  • Use <RouterLink> and <RouterView>.
  • Navigate programmatically.
  • Build a multi-page application.

3. Installation and Setup

bash
1
npm install vue-router@4
javascript
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849
// src/router/index.js
import { createRouter, createWebHistory } from &#039;vue-router&#039;

// Import view components
import HomeView from &#039;@/views/HomeView.vue&#039;

const router = createRouter({
  // createWebHistory: uses browser History API (clean URLs: /about)
  // createWebHashHistory: uses hash (/#/about) — works without server config
  history: createWebHistory(import.meta.env.BASE_URL),

  routes: [
    {
      path: &#039;/&#039;,
      name: &#039;home&#039;,
      component: HomeView
    },
    {
      path: &#039;/about&#039;,
      name: &#039;about&#039;,
      // Lazy loading — only downloads when user visits /about
      component: () => import(&#039;@/views/AboutView.vue&#039;)
    },
    {
      path: &#039;/products&#039;,
      name: &#039;products&#039;,
      component: () => import(&#039;@/views/ProductsView.vue&#039;)
    },
    {
      path: &#039;/products/:id&#039;,
      name: &#039;product-detail&#039;,
      component: () => import(&#039;@/views/ProductDetailView.vue&#039;)
    },
    {
      // Catch-all 404 route — MUST be last
      path: &#039;/:pathMatch(.*)*&#039;,
      name: &#039;not-found&#039;,
      component: () => import(&#039;@/views/NotFoundView.vue&#039;)
    }
  ],

  // Scroll to top on route change
  scrollBehavior(to, from, savedPosition) {
    if (savedPosition) return savedPosition
    return { top: 0 }
  }
})

export default router
javascript
123456
// src/main.js
import { createApp } from &#039;vue&#039;
import App from &#039;./App.vue&#039;
import router from &#039;./router&#039;

createApp(App).use(router).mount(&#039;#app&#039;)
vue
1234567891011121314151617181920212223242526272829303132
<!-- src/App.vue -->
<script setup>
import { RouterView, RouterLink } from &#039;vue-router'
</script>

<template>
  <!-- Navigation -->
  <nav>
    <!-- RouterLink renders as <a> tag but handles SPA navigation -->
    <RouterLink to="/">Home</RouterLink>
    <RouterLink to="/about">About</RouterLink>
    <RouterLink to="/products">Products</RouterLink>

    <!-- Named route -->
    <RouterLink :to="{ name: &#039;home' }">Home (named)</RouterLink>

    <!-- With params -->
    <RouterLink :to="{ name: &#039;product-detail', params: { id: 42 } }">
      Product 42
    </RouterLink>

    <!-- active-class: class added to current page&#039;s link -->
    <!-- router-link-active: partially matches /products and /products/1 -->
    <!-- router-link-exact-active: exact match only -->
    <RouterLink to="/products" active-class="my-active">Products</RouterLink>
  </nav>

  <!-- RouterView: renders the matched route component here -->
  <main>
    <RouterView />
  </main>
</template>

5. Programmatic Navigation

vue
123456789101112131415161718192021222324252627282930313233343536
<script setup>
import { useRouter, useRoute } from &#039;vue-router'

const router = useRouter()  // For navigation
const route = useRoute()    // For reading current route info

// Navigate to different routes
function goHome() {
  router.push(&#039;/')
}

function goToProduct(id) {
  // Push — adds to history
  router.push(`/products/${id}`)
  // Or with named route:
  router.push({ name: &#039;product-detail', params: { id } })
  // With query params: /products?category=electronics&sort=price
  router.push({ path: &#039;/products', query: { category: 'electronics' } })
}

function goBack() {
  router.go(-1)   // Go back 1 step (like browser back button)
}

function replaceRoute() {
  // Replace — replaces current history entry (no back button to previous)
  router.replace(&#039;/login')
}

// Read current route info
console.log(route.path)          // '/products/42'
console.log(route.params.id)     // '42'
console.log(route.query.sort)    // 'price'
console.log(route.name)          // 'product-detail'
console.log(route.fullPath)      // '/products/42?sort=price'
</script>

6. Mini Project: Multi-Page Application

javascript
12345678
// router/index.js for the blog app
const routes = [
  { path: &#039;/&#039;, name: &#039;home&#039;, component: () => import(&#039;@/views/HomeView.vue&#039;) },
  { path: &#039;/blog&#039;, name: &#039;blog&#039;, component: () => import(&#039;@/views/BlogView.vue&#039;) },
  { path: &#039;/blog/:slug&#039;, name: &#039;post&#039;, component: () => import(&#039;@/views/PostView.vue&#039;) },
  { path: &#039;/contact&#039;, name: &#039;contact&#039;, component: () => import(&#039;@/views/ContactView.vue&#039;) },
  { path: &#039;/:pathMatch(.*)*&#039;, component: () => import(&#039;@/views/NotFoundView.vue&#039;) }
]
vue
12345678910111213141516171819202122232425262728293031
<!-- App.vue — Navbar with active state styling -->
<template>
  <div id="app">
    <header>
      <nav class="navbar">
        <RouterLink to="/" class="brand">📖 VueBlog</RouterLink>
        <div class="nav-links">
          <RouterLink to="/">Home</RouterLink>
          <RouterLink to="/blog">Blog</RouterLink>
          <RouterLink to="/contact">Contact</RouterLink>
        </div>
      </nav>
    </header>
    <RouterView v-slot="{ Component }">
      <!-- Transition between pages -->
      <transition name="fade" mode="out-in">
        <component :is="Component" />
      </transition>
    </RouterView>
  </div>
</template>

<style>
.router-link-exact-active {
  color: #6366f1;
  font-weight: 700;
  border-bottom: 2px solid #6366f1;
}
.fade-enter-active, .fade-leave-active { transition: opacity .2s; }
.fade-enter-from, .fade-leave-to { opacity: 0; }
</style>

7. Common Mistakes

  • Using <a href="/about"> instead of <RouterLink to="/about">: Regular <a> tags cause full page reloads. Always use <RouterLink> for in-app navigation.
  • Not having a 404 catch-all route: Without /:pathMatch(.*)*, invalid URLs render nothing. Always add a 404 route as the last route.

8. MCQs

Question 1

What component renders the matched route?

Question 2

<RouterLink to="/about"> renders as?

Question 3

Lazy loading a route component uses?

Question 4

useRouter() gives access to?

Question 5

useRoute() gives access to?

Question 6

router.replace('/login') vs router.push('/login')?

Question 7

createWebHistory requires?

Question 8

Named routes are accessed with?

Question 9

router-link-exact-active class is added when?

Question 10

Catch-all 404 route path?

9. Interview Questions

  • Q: What is the difference between <RouterLink> and an HTML <a> tag?
  • Q: How does Vue Router enable SPA navigation without page reloads?

10. Summary

Vue Router transforms a Vue app into a full multi-page SPA. <RouterView> renders the current page's component. <RouterLink> navigates without reloads. useRouter enables programmatic navigation. useRoute reads current params and query strings. Lazy loading routes ensures fast initial load by splitting code.

11. Next Chapter Recommendation

In Chapter 15: Dynamic Routing and Navigation Guards, we explore route parameters, nested routes, and authentication guards that protect private pages.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·