Learn Vue - Routing & Navigation
Series/Learn Vue/Episode 9
Episode 9 of 24

Learn Vue - Routing & Navigation

This episode covers Vue Router: defining routes, dynamic and nested routes with lazy loading, scroll behavior and programmatic navigation, navigation guards, and route meta for protecting pages based on authentication needs.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Introduction

An application with a single page isn't enough. When you need a home page, a product detail page, and a profile page, you need routing — the way to map URLs to components. Vue Router is Vue's official router and the backbone of single-page application navigation.

Episode 9 covers it from the ground up: defining routes, dynamic and nested routes, lazy loading to keep the bundle lean, scroll behavior and programmatic navigation, navigation guards, and route meta for per-route authentication.

Vue Router Basics

Installing and Creating the Router

Install Vue Router, then define the route table:

Install Vue Router
npm install vue-router@4
JSRouter dasar
import { createRouter, createWebHistory } from "vue-router";
 
const router = createRouter({
  history: createWebHistory(),
  routes: [
    { path: "/", name: "home", component: HomeView },
    { path: "/tentang", name: "tentang", component: AboutView },
  ],
});
 
export default router;

createRouter({ history, routes }) builds the router; createWebHistory() uses the HTML5 History API so URLs are clean without a hash. Register the router with the app using createApp(App).use(router).mount("#app").

Templates display the active route through RouterView, and navigation uses RouterLink:

HTMLNavigasi dasar
<template>
  <nav>
    <RouterLink to="/">Home</RouterLink>
    <RouterLink to="/tentang">Tentang</RouterLink>
  </nav>
  <RouterView />
</template>

<RouterLink to="/"> renders as an anchor with client-side navigation and no reload, and <RouterView /> renders the component for the currently active route.

Dynamic and Nested Routes

Dynamic Routes

A detail page usually has a URL like /produk/42; its param is read through route.params.id after calling useRoute() in the component:

JSDynamic route
const routes = [
  { path: "/produk/:id", name: "detail", component: ProductDetail },
];

When the param changes, trigger a refetch with watch.

Nested Routes

Routes containing sub-pages are organized with children:

JSNested routes
const routes = [
  {
    path: "/akun",
    component: AkunLayout,
    children: [
      { path: "", component: AkunHome },
      { path: "pengaturan", component: AkunSetting },
    ],
  },
];

children are rendered inside AkunLayout through <RouterView />. This fits pages with tabs or a sidebar that share the same layout.

Lazy Loading Route Components

Don't import all pages at once; use dynamic imports so each page is fetched separately:

JSLazy loading rute
const routes = [
  {
    path: "/produk/:id",
    component: () => import("../views/ProductDetail.vue"),
  },
];

component: () => import(...) loads the page only when it's opened, splitting the code per route — the foundation of code splitting that we go deeper into in episode 14.

Global Guards

A guard runs before a navigation is completed. The most common example: checking authentication:

JSGlobal before guard
router.beforeEach((to, from, next) => {
  if (to.meta.requiresAuth && !isLogin()) {
    next({ name: "login", query: { redirect: to.fullPath } });
  } else {
    next();
  }
});

to.meta.requiresAuth reads the meta of the destination route; if login is required, it redirects to the login page with a redirect back.

Programmatic Navigation

Navigation can also be triggered from code with useRouter(), for example router.push({ name: "detail", params: { id } }) after a button is clicked, or router.back() to mimic the browser's back button.

Scroll Behavior and Route Props

Controlling Scroll Position

When moving between pages, scrollBehavior(to, from, savedPosition) in the router config returns the scroll position: use savedPosition when returning via history, or { top: 0 } for a fresh navigation.

Route Props

To keep a component independent of useRoute, enable props mode: { path: "/produk/:id", component: ProductDetail, props: true }. With props: true, :id is passed directly as an id prop, keeping the component clean and easy to test.

Route Meta and Per-Route Authentication

Meta for Per-Route Policies

Route meta can carry policy data, such as who is allowed to open a page:

JSRoute meta
const routes = [
  {
    path: "/admin",
    component: AdminView,
    meta: { requiresAuth: true, roles: ["admin"] },
  },
];

The guard then reads meta to enforce the policy: if to.meta.roles doesn't include the user's role, redirect to a forbidden page. to.meta.roles.includes(roleUser()) checks whether the user's role is in the allowed list — the basis of role-based access that we build out fully in episode 12.

Info

All route security logic on the client is only UI convenience. Real validation must still happen on the server — this applies to all subsequent security episodes.

Summary

Episode 9 took you from a single page to a multi-page application: defining routes with createRouter, dynamic and nested routes, per-route lazy loading, programmatic navigation, scroll behavior, route props, and meta and guards for per-route access policies.

Key takeaways:

  • RouterView renders the route; RouterLink navigates without reload.
  • A dynamic segment :id is read through route.params.
  • children creates nested routes with a shared layout.
  • Lazy-load all pages with () => import(...).
  • A beforeEach guard is great for authentication checks.
  • Route meta stores policies like allowed roles.

In the next episode 10, we'll cover modern state management — Pinia as Vue's official store, defining stores with state, getters, and actions, Pinia plugins, and best practices for state normalization and modular stores in large-scale applications.