Client-side routing with hash or history mode, transitions, guards, lazy loading, and nested routes.
import { createApp, createRouter } from 'courvux';
const router = createRouter([
{ path: '/', component: HomeComp },
{ path: '/about', component: AboutComp },
{ path: '/user/:id', component: UserComp },
{ path: '*', component: NotFoundComp } // catch-all
], {
mode: 'hash', // 'hash' (default) | 'history'
transition: 'fade', // global page transition
beforeEach(to, next) {
if (!isLoggedIn() && to.path !== '/login') next('/login');
else next();
},
scrollBehavior(_to, _from) { return { x: 0, y: 0 }; }
});
createApp({
router,
template: `
<nav>
<router-link to="/">Home</router-link>
<router-link to="/about">About</router-link>
</nav>
<router-view />
`
}).mount('#app');
// Route options
{
path: '/dashboard',
component: DashboardComp, // single view
components: { default: Main, panel: Sidebar }, // named views
redirect: '/home', // static redirect
redirect: (route) => `/new/${route.params.id}`, // dynamic
layout: `<aside>{{ $store.user }}</aside><router-view />`,
transition: 'slide-up', // per-route override
keepAlive: true, // cache DOM + state
meta: { requiresAuth: true },
loadingTemplate: '<p>Loading...</p>',
beforeEnter(to, next) { next(); }, // per-route guard
children: [...]
}
// Route definition
{ path: '/user/:id', component: UserComp }
// In UserComp template
<p>ID: {{ $route.params.id }}</p>
<p>Query: {{ $route.query.tab }}</p>
<p>Meta: {{ $route.meta.section }}</p>
| Property | Description |
|---|---|
$route.path | Current pathname, e.g. /user/42 |
$route.params | Path params — { id: '42' } |
$route.query | Query string as object — { page: '2' } |
$route.meta | Route-level metadata object |
// Dynamic import — loaded on first visit
{ path: '/dashboard', component: () => import('./dashboard.js') }
// dashboard.js
export default {
template: `<h1>Dashboard</h1>`,
data: { /* ... */ }
};
// With Vite and .html templates
import template from './dashboard.html?raw';
export default { template, data: {} };
// Programmatic navigation
methods: {
goHome() { this.$router.navigate('/'); },
goToUser(id) { this.$router.navigate(`/user/${id}`); },
goBack() { this.$router.back(); },
search(term) {
this.$router.navigate('/results', { query: { q: term } });
},
redirect(path) {
this.$router.replace(path); // no history entry
}
}
The parent component must contain a <router-view />. Child paths are relative to the parent.
{
path: '/panel',
component: {
template: `
<nav>
<router-link to="/panel/stats">Stats</router-link>
<router-link to="/panel/config">Config</router-link>
</nav>
<router-view /> <!-- child renders here <!-- child renders here -->
`
},
children: [
{ path: '/stats', component: StatsComp },
{ path: '/config', component: ConfigComp }
]
}