0
# Navigation Guards
1
2
Comprehensive guard system for controlling route transitions with global, per-route, and component-level hooks. Guards provide fine-grained control over navigation flow with support for authentication, authorization, and custom logic.
3
4
## Capabilities
5
6
### Global Guards
7
8
Router-wide navigation guards that apply to all route transitions.
9
10
```javascript { .api }
11
/**
12
* Global before guard - runs before every route transition
13
* @param guard - Navigation guard function
14
* @returns Function to remove the guard
15
*/
16
beforeEach(guard: NavigationGuard): () => void;
17
18
/**
19
* Global before resolve guard - runs after all component guards and async components are resolved
20
* @param guard - Navigation guard function
21
* @returns Function to remove the guard
22
*/
23
beforeResolve(guard: NavigationGuard): () => void;
24
25
/**
26
* Global after hook - runs after every route transition (cannot affect navigation)
27
* @param hook - After navigation hook function
28
* @returns Function to remove the hook
29
*/
30
afterEach(hook: (to: Route, from: Route) => any): () => void;
31
32
/**
33
* Navigation guard function signature
34
* @param to - Target route being navigated to
35
* @param from - Current route being navigated away from
36
* @param next - Function to call to resolve the hook
37
*/
38
type NavigationGuard = (to: Route, from: Route, next: NavigationGuardNext) => any;
39
40
/**
41
* Next function for controlling navigation flow
42
* @param to - Optional navigation target or false to abort
43
*/
44
type NavigationGuardNext = (to?: RawLocation | false | ((vm: Vue) => any) | void) => void;
45
```
46
47
**Usage Examples:**
48
49
```javascript
50
// Authentication guard
51
const removeGuard = router.beforeEach((to, from, next) => {
52
if (to.meta.requiresAuth && !isAuthenticated()) {
53
next('/login');
54
} else {
55
next();
56
}
57
});
58
59
// Authorization guard
60
router.beforeEach((to, from, next) => {
61
if (to.meta.roles && !hasRequiredRole(to.meta.roles)) {
62
next('/unauthorized');
63
} else {
64
next();
65
}
66
});
67
68
// Loading state management
69
router.beforeEach((to, from, next) => {
70
showLoadingSpinner();
71
next();
72
});
73
74
router.afterEach((to, from) => {
75
hideLoadingSpinner();
76
77
// Analytics tracking
78
trackPageView(to.path);
79
80
// Update page title
81
document.title = to.meta.title || 'My App';
82
});
83
84
// Remove guard when no longer needed
85
removeGuard();
86
```
87
88
### Route-Level Guards
89
90
Guards defined directly on route configurations.
91
92
```javascript { .api }
93
/**
94
* Route-level guard in route configuration
95
*/
96
interface RouteConfig {
97
beforeEnter?: NavigationGuard;
98
}
99
```
100
101
**Usage Examples:**
102
103
```javascript
104
const routes = [
105
{
106
path: '/admin',
107
component: AdminPanel,
108
beforeEnter: (to, from, next) => {
109
if (!hasAdminAccess()) {
110
next('/dashboard');
111
} else {
112
next();
113
}
114
}
115
},
116
{
117
path: '/user/:id',
118
component: UserProfile,
119
beforeEnter: async (to, from, next) => {
120
try {
121
// Validate user exists and is accessible
122
await validateUserAccess(to.params.id);
123
next();
124
} catch (error) {
125
next('/not-found');
126
}
127
}
128
}
129
];
130
```
131
132
### Component Guards
133
134
Guards defined within Vue component definitions.
135
136
```javascript { .api }
137
/**
138
* Component-level navigation guards (defined in component options)
139
*/
140
interface ComponentGuards {
141
/** Called when route is about to change but component is reused */
142
beforeRouteUpdate?: NavigationGuard;
143
/** Called before navigating away from this component */
144
beforeRouteLeave?: NavigationGuard;
145
/** Called when this route is confirmed (after all guards pass) */
146
beforeRouteEnter?: (to: Route, from: Route, next: (callback?: (vm: any) => any) => void) => any;
147
}
148
```
149
150
**Usage Examples:**
151
152
```javascript
153
// In component definition
154
export default {
155
name: 'UserProfile',
156
157
beforeRouteEnter(to, from, next) {
158
// Component instance not yet created, so no access to `this`
159
getUserData(to.params.id).then(user => {
160
next(vm => {
161
// Access component instance via callback
162
vm.setUser(user);
163
});
164
});
165
},
166
167
beforeRouteUpdate(to, from, next) {
168
// Component is reused, so `this` is available
169
this.loadUser(to.params.id);
170
next();
171
},
172
173
beforeRouteLeave(to, from, next) {
174
if (this.hasUnsavedChanges) {
175
const confirmed = confirm('You have unsaved changes. Are you sure you want to leave?');
176
if (confirmed) {
177
next();
178
} else {
179
next(false); // Cancel navigation
180
}
181
} else {
182
next();
183
}
184
}
185
};
186
```
187
188
### Composition API Guards
189
190
Guards for use with composition API (Vue 2.7+ or @vue/composition-api).
191
192
```javascript { .api }
193
/**
194
* Composition API guard for route updates
195
* @param guard - Navigation guard to register
196
*/
197
function onBeforeRouteUpdate(guard: NavigationGuard): void;
198
199
/**
200
* Composition API guard for route leave
201
* @param guard - Navigation guard to register
202
*/
203
function onBeforeRouteLeave(guard: NavigationGuard): void;
204
```
205
206
**Usage Examples:**
207
208
```javascript
209
import { onBeforeRouteUpdate, onBeforeRouteLeave } from 'vue-router/composables';
210
211
export default {
212
setup() {
213
const hasUnsavedChanges = ref(false);
214
215
onBeforeRouteUpdate((to, from, next) => {
216
// Handle route parameter changes
217
if (to.params.id !== from.params.id) {
218
loadUserData(to.params.id);
219
}
220
next();
221
});
222
223
onBeforeRouteLeave((to, from, next) => {
224
if (hasUnsavedChanges.value) {
225
const confirmed = confirm('Leave without saving?');
226
next(confirmed);
227
} else {
228
next();
229
}
230
});
231
232
return {
233
hasUnsavedChanges
234
};
235
}
236
};
237
```
238
239
### Navigation Flow Control
240
241
Control navigation behavior using the next function.
242
243
```javascript { .api }
244
/**
245
* Navigation control options for next() function
246
*/
247
type NavigationGuardNext = (
248
/** Continue navigation normally */
249
to?: void |
250
/** Abort current navigation */
251
false |
252
/** Redirect to different location */
253
RawLocation |
254
/** Execute callback when navigation confirmed (beforeRouteEnter only) */
255
((vm: Vue) => any)
256
) => void;
257
```
258
259
**Usage Examples:**
260
261
```javascript
262
router.beforeEach((to, from, next) => {
263
// Continue navigation
264
next();
265
266
// Abort navigation
267
next(false);
268
269
// Redirect to different route
270
next('/login');
271
next({ name: 'login', query: { redirect: to.fullPath }});
272
273
// Multiple conditions
274
if (!isAuthenticated()) {
275
next('/login');
276
} else if (!hasPermission(to.meta.permission)) {
277
next('/unauthorized');
278
} else {
279
next();
280
}
281
});
282
283
// Callback usage in beforeRouteEnter
284
beforeRouteEnter(to, from, next) {
285
fetchUserData(to.params.id).then(userData => {
286
next(vm => {
287
vm.userData = userData;
288
});
289
});
290
}
291
```
292
293
### Error Handling in Guards
294
295
Handle errors and failed navigation attempts.
296
297
```javascript { .api }
298
/**
299
* Navigation error types
300
*/
301
enum NavigationFailureType {
302
aborted = 4,
303
cancelled = 8,
304
duplicated = 16,
305
redirected = 2
306
}
307
308
/**
309
* Check if error is a navigation failure
310
* @param error - Error to check
311
* @param type - Optional specific failure type to check for
312
* @returns True if error is navigation failure of specified type
313
*/
314
function isNavigationFailure(error: any, type?: NavigationFailureType): boolean;
315
```
316
317
**Usage Examples:**
318
319
```javascript
320
import { isNavigationFailure, NavigationFailureType } from 'vue-router';
321
322
// Handle navigation errors
323
router.push('/some-route').catch(error => {
324
if (isNavigationFailure(error, NavigationFailureType.aborted)) {
325
console.log('Navigation was aborted');
326
} else if (isNavigationFailure(error, NavigationFailureType.duplicated)) {
327
console.log('Navigation to same location');
328
} else {
329
console.error('Navigation error:', error);
330
}
331
});
332
333
// Global error handling
334
router.onError(error => {
335
console.error('Router error:', error);
336
// Handle errors globally
337
});
338
339
// Guard error handling
340
router.beforeEach(async (to, from, next) => {
341
try {
342
await validateRoute(to);
343
next();
344
} catch (error) {
345
console.error('Route validation failed:', error);
346
next('/error');
347
}
348
});
349
```
350
351
### Guard Execution Order
352
353
Understanding the complete navigation resolution flow.
354
355
```javascript { .api }
356
/**
357
* Complete navigation resolution flow:
358
* 1. Navigation triggered
359
* 2. Call beforeRouteLeave guards in deactivated components
360
* 3. Call global beforeEach guards
361
* 4. Call beforeRouteUpdate guards in reused components
362
* 5. Call beforeEnter in route configs
363
* 6. Resolve async route components
364
* 7. Call beforeRouteEnter in activated components
365
* 8. Call global beforeResolve guards
366
* 9. Navigation confirmed
367
* 10. Call global afterEach hooks
368
* 11. DOM updates triggered
369
* 12. Call callbacks passed to next in beforeRouteEnter guards
370
*/
371
```
372
373
**Usage Example:**
374
375
```javascript
376
// Complete guard setup demonstrating execution order
377
export default {
378
// Component guard (step 7)
379
beforeRouteEnter(to, from, next) {
380
console.log('7. beforeRouteEnter');
381
next();
382
},
383
384
// Component guard (step 4)
385
beforeRouteUpdate(to, from, next) {
386
console.log('4. beforeRouteUpdate');
387
next();
388
},
389
390
// Component guard (step 2)
391
beforeRouteLeave(to, from, next) {
392
console.log('2. beforeRouteLeave');
393
next();
394
}
395
};
396
397
// Route config guard (step 5)
398
const routes = [{
399
path: '/example',
400
component: ExampleComponent,
401
beforeEnter: (to, from, next) => {
402
console.log('5. beforeEnter');
403
next();
404
}
405
}];
406
407
// Global guards
408
router.beforeEach((to, from, next) => {
409
console.log('3. global beforeEach');
410
next();
411
});
412
413
router.beforeResolve((to, from, next) => {
414
console.log('8. global beforeResolve');
415
next();
416
});
417
418
router.afterEach((to, from) => {
419
console.log('10. global afterEach');
420
});
421
```
422
423
## Types
424
425
```javascript { .api }
426
interface NavigationFailure extends Error {
427
from: Route;
428
to: Route;
429
type: NavigationFailureType.aborted | NavigationFailureType.cancelled | NavigationFailureType.duplicated;
430
}
431
432
type ErrorHandler = (err: Error) => void;
433
```