Vue Router

Vue Router maps URL paths to components, so a single-page Vue app can present multiple views with shareable, bookmarkable URLs and working browser back/forward buttons.

Defining Routes

A route is just an object pairing a path with the component that should render at that path. You collect these into a routes array and hand them, along with a history mode, to createRouter. createWebHistory gives you clean URLs backed by the browser's History API; the resulting router instance is then installed on the app with app.use(router), which is what makes router-view and router-link available everywhere in the app.

Configuring the Router

// router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
import AboutView from '../views/AboutView.vue'
import UserView from '../views/UserView.vue'

const router = createRouter({
  history: createWebHistory(),
  routes: [
    { path: '/', name: 'home', component: HomeView },
    { path: '/about', name: 'about', component: AboutView },
    { path: '/users/:id', name: 'user', component: UserView }
  ]
})

export default router

// main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'

createApp(App).use(router).mount('#app')

router-view and router-link

router-view is a placeholder component that renders whichever component matches the current URL -- think of it as the outlet the router fills in. router-link renders an anchor tag whose href is generated from a to prop, and it intercepts clicks so navigation happens through the router instead of triggering a full page reload, keeping your app's in-memory state intact.

Navigation and the View Outlet

<!-- App.vue -->
<template>
  <nav>
    <router-link to='/'>Home</router-link>
    <router-link to='/about'>About</router-link>
    <router-link :to="{ name: 'user', params: { id: 42 } }">User 42</router-link>
  </nav>

  <router-view></router-view>
</template>

Reading Params and Navigating in Script

Inside <script setup>, two composables replace the this.$route and this.$router you may have seen in the Options API: useRoute() returns the current, reactive route object -- path, params, query -- and useRouter() returns the router instance so you can call methods like push, replace, and back. Both must be called at the top level of setup, the same rule that applies to any Composition API function.

useRoute and useRouter in Practice

<!-- UserView.vue -->
<script setup>
import { useRoute, useRouter } from 'vue-router'

const route = useRoute()
const router = useRouter()

function goToNextUser() {
  const nextId = Number(route.params.id) + 1
  router.push({ name: 'user', params: { id: nextId } })
}
</script>

<template>
  <h2>Viewing user #{{ route.params.id }}</h2>
  <button @click='goToNextUser'>Next user</button>
  <button @click='router.back()'>Go back</button>
</template>

Comparing Your Options

TaskTemplate wayScript way
Link to a pagerouter-link to='/about'router.push('/about')
Read the current path or paramsNot applicable, use scriptuseRoute() (Composition) or this.$route (Options)
Trigger navigation from codeNot applicable, use a link or scriptuseRouter() (Composition) or this.$router (Options)
Note: Prefer router-link for anything the user clicks -- it produces a real anchor tag, so middle-click, right-click 'open in new tab', and screen readers all work the way users expect. Reach for router.push() only when navigation should follow non-click logic, like after a form submits successfully.
Note: Route params are strings even when they look numeric. route.params.id will be '42', not 42 -- convert it with Number() before doing arithmetic, exactly as the goToNextUser example above does.

Exercise: Vue Router

Why use <router-link> instead of a plain <a> tag for internal navigation?