Vue.js Router

Vue Router is the official routing library for Vue.js. It lets you build multi-page applications where different URLs show different components — without ever reloading the browser page. The user navigates between pages and the URL updates, but only the content area changes.

What Routing Does

In a traditional website, clicking a link loads an entirely new HTML page from the server. In a Vue single-page application (SPA), the browser loads one HTML file and Vue Router swaps components in and out based on the URL.

Diagram: Traditional Website vs Vue Router SPA

Traditional Website:
  User visits /home   → Server sends home.html  (full page load)
  User visits /about  → Server sends about.html (full page load)
  User visits /contact→ Server sends contact.html (full page load)
  Each click = complete page refresh

Vue SPA with Router:
  Browser loads index.html once
  User visits /home   → Vue renders HomeView component  (instant)
  User visits /about  → Vue renders AboutView component (instant)
  User visits /contact→ Vue renders ContactView component (instant)
  No page refresh — only the content area changes

Installation

When creating a project with Vite, select "Yes" for Vue Router. For an existing project, install it with:

npm install vue-router@4

Setting Up Vue Router

You define routes in a configuration file, create the router, and plug it into your Vue app.

Step 1: Create the Router File

// src/router/index.js
import { createRouter, createWebHistory } from "vue-router";
import HomeView    from "../views/HomeView.vue";
import AboutView   from "../views/AboutView.vue";
import ContactView from "../views/ContactView.vue";

const routes = [
  { path: "/",        component: HomeView },
  { path: "/about",   component: AboutView },
  { path: "/contact", component: ContactView }
];

const router = createRouter({
  history: createWebHistory(),
  routes
});

export default router;

Step 2: Register the Router in main.js

// src/main.js
import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";

createApp(App).use(router).mount("#app");

Step 3: Add RouterView to App.vue

<!-- src/App.vue -->
<template>
  <nav>
    <RouterLink to="/">Home</RouterLink>
    <RouterLink to="/about">About</RouterLink>
    <RouterLink to="/contact">Contact</RouterLink>
  </nav>

  <RouterView />   <!-- Active component renders here -->
</template>

Diagram: RouterView and RouterLink

App.vue layout:
┌──────────────────────────────────────────┐
│  NAV: [Home] [About] [Contact]           │  ← RouterLink
├──────────────────────────────────────────┤
│                                          │
│  <RouterView />                          │
│  (shows HomeView, AboutView, or          │
│   ContactView based on URL)              │
│                                          │
└──────────────────────────────────────────┘

URL = "/"        → RouterView renders HomeView
URL = "/about"   → RouterView renders AboutView
URL = "/contact" → RouterView renders ContactView

RouterLink — Navigation Without Page Reload

<RouterLink> renders as an <a> tag but intercepts the click and updates the URL without reloading the page. It also adds an active class automatically when the current URL matches its to prop.

<RouterLink to="/about">About Us</RouterLink>
<!-- Renders as: <a href="/about">About Us</a> -->

<!-- When the URL is /about: -->
<!-- <a href="/about" class="router-link-active">About Us</a> -->

Dynamic Routes — URL Parameters

Dynamic segments in a route path start with a colon. They capture a value from the URL and make it available to the component.

// router/index.js
const routes = [
  { path: "/user/:id",         component: UserView },
  { path: "/product/:slug",    component: ProductView }
];
<!-- These all match /user/:id -->
<RouterLink to="/user/42">User 42</RouterLink>
<RouterLink to="/user/99">User 99</RouterLink>

Accessing the Route Parameter

<!-- UserView.vue -->
<template>
  <h2>User Profile: {{ userId }}</h2>
</template>

<script setup>
import { useRoute } from "vue-router";

const route  = useRoute();
const userId = route.params.id;   // "42" or "99" etc.
</script>

Diagram: Dynamic Route Matching

Route definition:  /user/:id

URL /user/42  →  UserView loads, route.params.id = "42"
URL /user/99  →  UserView loads, route.params.id = "99"
URL /user/sam →  UserView loads, route.params.id = "sam"

Nested Routes

Routes can be nested inside parent routes. A child route renders inside the parent component's own <RouterView>.

const routes = [
  {
    path: "/dashboard",
    component: DashboardView,
    children: [
      { path: "",         component: DashboardHome },
      { path: "stats",    component: DashboardStats },
      { path: "settings", component: DashboardSettings }
    ]
  }
];

Diagram: Nested Route Rendering

URL: /dashboard
┌──────────────────────────────────────────┐
│  DashboardView                           │
│  [Home] [Stats] [Settings]  ← links      │
│  ┌────────────────────────┐              │
│  │ <RouterView />         │              │
│  │ renders DashboardHome  │              │
│  └────────────────────────┘              │
└──────────────────────────────────────────┘

URL: /dashboard/stats
┌──────────────────────────────────────────┐
│  DashboardView                           │
│  [Home] [Stats] [Settings]               │
│  ┌────────────────────────┐              │
│  │ <RouterView />         │              │
│  │ renders DashboardStats │              │
│  └────────────────────────┘              │
└──────────────────────────────────────────┘

Programmatic Navigation

Navigate from JavaScript (not just links) using the router object.

<script setup>
import { useRouter } from "vue-router";

const router = useRouter();

function goToProfile(userId) {
  router.push("/user/" + userId);
}

function goBack() {
  router.back();
}

function goHome() {
  router.push({ path: "/" });
}

// Named route navigation
function goToProduct(slug) {
  router.push({ name: "product", params: { slug } });
}
</script>

Named Routes

Give routes a name so you can navigate to them by name instead of hardcoded paths. This makes refactoring easier — if the path changes, only the route definition needs updating.

const routes = [
  { path: "/product/:slug", name: "product", component: ProductView },
  { path: "/user/:id",      name: "user",    component: UserView }
];
<RouterLink :to="{ name: 'user', params: { id: 42 } }">
  View User
</RouterLink>

Route Guards — Protecting Pages

Route guards run before a navigation happens. Use them to restrict access to certain routes — for example, preventing unauthenticated users from reaching a dashboard.

// Global guard — runs before every route change
router.beforeEach((to, from, next) => {
  const isLoggedIn = localStorage.getItem("token");

  if (to.meta.requiresAuth && !isLoggedIn) {
    next("/login");    // redirect to login page
  } else {
    next();            // allow navigation
  }
});
// Mark protected routes with meta
const routes = [
  { path: "/dashboard", component: Dashboard, meta: { requiresAuth: true } },
  { path: "/login",     component: Login }
];

Diagram: Guard Decision Flow

User navigates to /dashboard
        │
        ▼
beforeEach guard runs
        │
  requiresAuth = true
  isLoggedIn = false?
        │
   Yes  │   No
        │         └──▶ next() → /dashboard loads ✓
        ▼
  next("/login")
  → Redirected to /login

404 — Catch-All Route

Add a catch-all route at the end of your routes array to show a "not found" page for any unmatched URL.

const routes = [
  { path: "/",      component: HomeView },
  { path: "/about", component: AboutView },
  // Must be last:
  { path: "/:pathMatch(.*)*", name: "not-found", component: NotFoundView }
];

Summary

Vue Router maps URLs to components and swaps them into the <RouterView> without page reloads. Define routes as path-to-component pairs and register the router with app.use(router). Use <RouterLink> for navigation links. Dynamic segments like :id capture URL values accessible through route.params. Nest routes to build multi-level layouts. Navigate from code using router.push(). Protect routes with guards in beforeEach(). Use a catch-all route to handle unknown URLs gracefully.

Leave a Comment

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