Skip to content

Programmatic Navigation and Guards

<RouterLink> handles declarative navigation — the user clicks a link. But often you need to navigate in response to events, form submissions, or conditions. That’s programmatic navigation.

useRouter() returns the router instance. Call router.push() to navigate:

<script setup lang="ts">
import { useRouter } from 'vue-router'
const router = useRouter()
function handleSubmit(personId: string) {
// After saving, navigate to the detail page
router.push({ name: 'person', params: { id: personId } })
}
function goHome() {
router.push({ name: 'home' })
}
</script>

router.push() adds an entry to the browser history — the back button works. router.replace() replaces the current entry instead — the back button skips the replaced page.

PersonDetailView.vue uses programmatic navigation when the user deletes a person:

function handleDelete() {
if (!confirm(`Delete ${person.value?.name}? This cannot be undone.`)) return
store.deletePerson(id)
router.push({ name: 'home' }) // return home after deletion
}
function focusOn(pid: string) {
store.setFocus(pid)
router.push({ name: 'home' }) // navigate to home with new focus
}

Guards intercept navigation and can allow, redirect, or cancel it. The most common is the global beforeEach guard, registered on the router:

router.beforeEach((to, from) => {
// to: the route being navigated to
// from: the route being navigated from
// Return false to cancel navigation
// Return a route location to redirect
// Return nothing (or true) to allow
})

A simple guard that requires data before viewing a person’s details:

router.beforeEach((to, from) => {
if (to.name === 'person') {
const store = useFamilyStore()
const exists = store.people.some(p => p.id === to.params.id)
if (!exists) {
return { name: 'home' } // redirect home if person doesn't exist
}
}
})

Guards can also be defined on individual route records:

{
path: '/admin',
component: AdminView,
beforeEnter: (to, from) => {
if (!isAdmin()) return { name: 'home' }
}
}
  1. Add programmatic navigation to a form’s submit handler: after “saving” (just console.log for now), push to { name: 'home' }.
  2. Add a global beforeEach guard that logs "Navigating to: " + to.name for every navigation.
  3. Extend the guard to redirect to { name: 'home' } if the user tries to navigate to { name: 'person' } with an id that doesn’t exist in the store.
  • useRouter() returns the router instance; call router.push(location) to navigate programmatically.
  • router.push() adds history; router.replace() replaces the current entry.
  • router.beforeEach((to, from) => {...}) runs before every navigation — return a route to redirect, false to cancel, or nothing to allow.
  • Per-route beforeEnter guards work the same way for a single route.