Nested routes
Nested routes are needed when a group of pages shares a part: a blog admin section with its own menu, inside which "All posts" and "New post" change. The parent route renders the layout, and the child routes render the content inside it.
The section layout
Create src/views/AdminLayout.vue. It has its own RouterView — child pages go there:
<!-- src/views/AdminLayout.vue -->
<template>
<section class="admin">
<h1>Blog admin</h1>
<nav>
<RouterLink :to="{ name: 'admin-posts' }">All posts</RouterLink> |
<RouterLink :to="{ name: 'admin-new-post' }">New post</RouterLink>
</nav>
<RouterView />
</section>
</template>And two simple pages:
<!-- src/views/AdminPostsView.vue -->
<template>
<h2>All posts</h2>
<p>A table of posts goes here.</p>
</template><!-- src/views/NewPostView.vue -->
<template>
<h2>New post</h2>
<p>A form goes here.</p>
</template>Child routes
Child routes are listed in the children field. Their paths are written without a leading slash — they are appended to the parent's path:
// src/router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{ path: '/', name: 'home', component: HomeView },
{ path: '/about', name: 'about', component: () => import('../views/AboutView.vue') },
{ path: '/posts/:id', name: 'post', component: () => import('../views/PostView.vue') },
{
path: '/admin',
component: () => import('../views/AdminLayout.vue'),
children: [
{ path: '', name: 'admin-posts', component: () => import('../views/AdminPostsView.vue') },
{ path: 'new', name: 'admin-new-post', component: () => import('../views/NewPostView.vue') },
],
},
{ path: '/:pathMatch(.*)*', name: 'not-found', component: () => import('../views/NotFoundView.vue') },
],
})
export default routerOpen http://localhost:5173/admin — you see the heading "Blog admin", the menu and "All posts". At /admin/new the layout stays, and the content inside changes to "New post".
| Address | What is rendered |
|---|---|
/admin | AdminLayout with AdminPostsView inside |
/admin/new | AdminLayout with NewPostView inside |
/anything | NotFoundView |
Lazy loading
component: () => import('...') loads a page's code only on the first visit to it. In the build each such page goes into a separate file, and the home page opens faster. The page everyone sees — the home page — is usually imported directly.
The 404 page
The last route with the path /:pathMatch(.*)* matches any address no other route matched. Create src/views/NotFoundView.vue for it:
<!-- src/views/NotFoundView.vue -->
<template>
<h1>Page not found</h1>
<RouterLink to="/">Home</RouterLink>
</template>The address http://localhost:5173/abc shows "Page not found".
Common mistake
Forgetting RouterView in the parent layout. The address /admin/new opens without errors but shows only the heading and menu — the child page has nowhere to render. Every nesting level needs its own RouterView.