Navigation Guards and Advanced Routing

By Syncfusion®, Inc. · Last updated

Global guards (beforeEach, beforeResolve, afterEach), per-route beforeEnter, in-component onBeforeRouteLeave and onBeforeRouteUpdate, typed route meta, an auth guard with a redirect back, fetching data before or after navigation, scroll behaviour, lazy-loaded routes and moving focus after navigation.

Guarding Navigation

  • Some pages must not open for everyone. The kitchen screen is for staff only.
  • Some pages must not close too easily. A half-filled form should warn first.
  • A navigation guard = a function the router calls before or after moving to a page.
  • A guard can allow, cancel or redirect the move.

Simple lesson: guards decide whether a navigation may happen.

A Real-World Example

  • Meera's site has a staff-only page: /kitchen.
  • A visitor who is not logged in must go to /login instead.
  • After logging in, they must land back on /kitchen.
  • What happened: "Kitchen" sent you to /login?redirect=/kitchen.
  • After logging in, the login page pushed you back to /kitchen.

What You Will Learn

  1. The global guards and their order.
  2. What a guard can return.
  3. Guards on one route.
  4. Guards inside a component.
  5. Route meta, typed in TypeScript.
  6. Loading data before or after a page opens.
  7. Scroll behaviour.
  8. Lazy-loaded routes.
  9. Moving focus after navigation.

Global Guards

  • router.beforeEach((to, from) => ...) runs before every navigation.
  • router.beforeResolve(...) runs last, just before the move is confirmed.
  • router.afterEach((to, from) => ...) runs after the move. It cannot cancel anything.
  • A guard can return:

    • nothing or true: allow
    • false: cancel
    • a path or route object: redirect
  • A guard can be async. The router waits for it.
  • Older code uses a third argument, next(). Returning a value is the modern way. Never mix both.
  • Do not guard the page you redirect to. If /login also needs a login, the router loops forever.

Animation: a navigation passes through beforeEach, beforeEnter, in-component guards, beforeResolve, then the page changes and afterEach runs. A guard that returns false stops the dot

beforeEach beforeEnter in-component beforeResolve afterEach

Every guard allowed it: the page changes

beforeEnter returned false: cancelled

Guards run in order. Any guard can stop or redirect the navigation.

  • What happened: the Console shows the guards in order.
  • "B (closed)" was cancelled by beforeEnter, and afterEach reported it.

Simple lesson: return nothing to allow, false to cancel, a route to redirect.

In-Component Guards

  • onBeforeRouteLeave runs when leaving this page. Use it to protect unsaved work.
  • onBeforeRouteUpdate runs when the same page is reused with new params, such as /dish/1 → /dish/2.
  • Both come from vue-router and must be called in <script setup>.

Real apps often ask with window.confirm("Leave without saving?") in onBeforeRouteLeave. This lab shows a warning on the page instead, because pop-up dialogs block the preview.

Route Meta and Auth

  • meta = extra data on a route, such as { requiresAuth: true, title: "Menu" }.
  • Guards read it: to.meta.requiresAuth.
  • Meta of parent routes is merged into children.
  • In TypeScript, add your fields to the RouteMeta interface with declare module "vue-router", as in the first box.
  • Keep the page the user wanted in query.redirect, and send them back after login.

Fetching Data and Navigation

WayHowUser sees
Fetch after navigationLoad in the page (onMounted, or watch on params)The new page at once, with a loading message
Fetch before navigationLoad in beforeEnter or beforeResolve, then allowThe old page until data is ready
  • Fetching before lets a guard redirect when the data does not exist.

beforeEnter runs only when you enter the route from another route. Going from /dish/2 to /dish/3 does not run it again. Use onBeforeRouteUpdate, or a watch on the params, for that case.

Scroll, Lazy Loading and Focus

  • Scroll behaviour: scrollBehavior(to, from, saved) in createRouter decides where to scroll. Return saved for Back, { el: to.hash } for anchors, or { top: 0 }.
  • Lazy loading: component: () => import("./views/Big.vue") loads a page only when it is first visited. The first bundle stays small.
  • Focus: after a page change, screen-reader users need to know. Move focus to the new page's heading in afterEach.

In a real build, each lazy route becomes its own JavaScript file, loaded over the network on the first visit. In this lab, all files are already in the preview, so "loaded only now" shows when the code first runs, not a network download.

Simple lesson: lazy-load big pages, scroll sensibly, and move focus to the new heading.

TL;DR

  • Navigation guard = a function that can allow, cancel or redirect a navigation.
  • beforeEach / beforeResolve / afterEach = global: first / last before confirm / after.
  • Return values = nothing = allow, false = cancel, a route = redirect.
  • beforeEnter = a guard on one route. Only on entering it.
  • onBeforeRouteLeave / onBeforeRouteUpdate = in-component: leaving / same page, new params.
  • Route meta = extra route data. Type it with RouteMeta.
  • Fetch before / after = in a guard / in the page.
  • Lazy route = component: () => import("./Page.vue").
  • scrollBehavior and focus = where to scroll / focus the new heading in afterEach.

Common mistakes

MistakeWrong ideaCorrect ideaWhat goes wrong
Auth check in every pageEach page should checkOne beforeEach with meta.requiresAuthA forgotten page is left open
Redirecting to the same guarded pageThe guard runs onceRedirect to a page that is allowedAn endless redirect loop
Expecting beforeEnter on param changeIt runs on every visitUse onBeforeRouteUpdate or watchOld data on the new param
Cancelling in afterEachIt can still stop navigationCancel in a before guardThe page has already changed
Losing the wanted page on loginSend users home after loginKeep query.redirect and push itUsers must find the page again
Lazy-loading every tiny pageLazy is always fasterLazy-load big or rare pagesMany tiny downloads
No focus change after navigationScreen readers notice by themselvesFocus the new page's headingScreen-reader users miss the change

Check Yourself

Exercises

What to Remember

  • Guards can allow, cancel (false) or redirect (a route).
  • Put auth in one beforeEach, driven by route meta.
  • onBeforeRouteLeave protects unsaved work. onBeforeRouteUpdate handles new params.
  • Fetch before navigation to redirect on missing data, or after it to show a loader.
  • Lazy-load big pages, and focus the new heading after navigation.

Next: State Management with Pinia