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
/logininstead. - 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
- The global guards and their order.
- What a guard can return.
- Guards on one route.
- Guards inside a component.
- Route meta, typed in TypeScript.
- Loading data before or after a page opens.
- Scroll behaviour.
- Lazy-loaded routes.
- 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
- nothing or
- 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
/loginalso 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, andafterEachreported it.
Simple lesson: return nothing to allow, false to cancel, a route to redirect.
In-Component Guards
onBeforeRouteLeaveruns when leaving this page. Use it to protect unsaved work.onBeforeRouteUpdateruns when the same page is reused with new params, such as/dish/1→/dish/2.- Both come from
vue-routerand 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
RouteMetainterface withdeclare 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
| Way | How | User sees |
|---|---|---|
| Fetch after navigation | Load in the page (onMounted, or watch on params) | The new page at once, with a loading message |
| Fetch before navigation | Load in beforeEnter or beforeResolve, then allow | The 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)increateRouterdecides where to scroll. Returnsavedfor 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"). scrollBehaviorand focus = where to scroll / focus the new heading inafterEach.
Common mistakes
| Mistake | Wrong idea | Correct idea | What goes wrong |
|---|---|---|---|
| Auth check in every page | Each page should check | One beforeEach with meta.requiresAuth | A forgotten page is left open |
| Redirecting to the same guarded page | The guard runs once | Redirect to a page that is allowed | An endless redirect loop |
Expecting beforeEnter on param change | It runs on every visit | Use onBeforeRouteUpdate or watch | Old data on the new param |
Cancelling in afterEach | It can still stop navigation | Cancel in a before guard | The page has already changed |
| Losing the wanted page on login | Send users home after login | Keep query.redirect and push it | Users must find the page again |
| Lazy-loading every tiny page | Lazy is always faster | Lazy-load big or rare pages | Many tiny downloads |
| No focus change after navigation | Screen readers notice by themselves | Focus the new page's heading | Screen-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 routemeta. onBeforeRouteLeaveprotects unsaved work.onBeforeRouteUpdatehandles 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