# NProgress Integration in Vue-Element-Admin's Router beforeEach Guard: A Complete Guide

> Learn how to integrate NProgress into Vue-Element-Admin's beforeEach guard for seamless loading bar displays during route navigation. Enhance user experience now.

- Repository: [花裤衩/vue-element-admin](https://github.com/PanJiaChen/vue-element-admin)
- Tags: how-to-guide
- Published: 2026-02-27

---

**NProgress displays a slim progress bar during route navigation by starting in `router.beforeEach` and completing in `router.afterEach` inside [`src/permission.js`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/permission.js).**

Vue-Element-Admin implements a seamless loading state using **NProgress** to provide visual feedback while authentication checks and async route resolution occur. The integration lives entirely within the global navigation guards in [`src/permission.js`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/permission.js), ensuring users see activity whenever the router is busy processing permissions or fetching user data.

## How NProgress Works in the Router Guard

The implementation follows a strict lifecycle: start immediately on navigation intent, then resolve explicitly on redirects, errors, or successful completion.

### Configuration and Initial Setup

The library is imported and configured at the top of [`src/permission.js`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/permission.js) to disable the default spinner and show only the thin top bar:

```javascript
import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css'

NProgress.configure({ showSpinner: false })

```

This configuration removes the spinning indicator (lines 4‑9), leaving a minimal progress bar that matches the admin dashboard’s clean aesthetic.

### Starting the Progress Bar

Every navigation request triggers `NProgress.start()` inside the `router.beforeEach` guard before any async logic executes:

```javascript
router.beforeEach(async(to, from, next) => {
  NProgress.start()
  // Token validation and permission checks follow...
})

```

Located at lines 13‑16, this ensures the bar appears instantly when a user clicks a link, even while the app fetches user info or generates accessible routes.

### Handling Redirects and Error States

The guard manually calls `NProgress.done()` in three specific scenarios to prevent the bar from hanging when navigation is aborted:

**Redirecting authenticated users from login:**
When a logged-in user attempts to access `/login`, the guard redirects to `/` and immediately clears the bar (lines 24‑28):

```javascript
if (to.path === '/login') {
  next({ path: '/' })
  NProgress.done() // hack: https://github.com/PanJiaChen/vue-element-admin/pull/2938
}

```

**Handling authentication failures:**
If `store.dispatch('user/getInfo')` throws an error, the guard catches it, displays a message, redirects to login, and clears the progress bar (lines 48‑54):

```javascript
Message.error(error || 'Has Error')
next(`/login?redirect=${to.path}`)
NProgress.done()

```

**Blocking unauthenticated access:**
For users without a valid token accessing protected routes, the guard redirects to login and completes the progress (lines 63‑66):

```javascript
next(`/login?redirect=${to.path}`)
NProgress.done()

```

### Completing Successful Navigation

The final safety net resides in `router.afterEach`, which guarantees the bar disappears once navigation finishes, covering cases where the `beforeEach` guard did not manually call `done()` (lines 71‑74):

```javascript
router.afterEach(() => {
  NProgress.done()
})

```

## Practical Implementation Examples

### Minimal Standalone Guard

To replicate the Vue-Element-Admin pattern in any Vue Router project:

```javascript
// router/guard.js
import router from './index'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'

NProgress.configure({ showSpinner: false })

router.beforeEach((_to, _from, next) => {
  NProgress.start()
  next()
})

router.afterEach(() => {
  NProgress.done()
})

```

### Custom Async Guard with Error Handling

When implementing complex permission checks, wrap async logic and ensure `done()` fires in the `finally` block:

```javascript
router.beforeEach(async (to, from, next) => {
  NProgress.start()
  try {
    await fetchPermissions(to.meta.requiredRoles)
    next()
  } catch (e) {
    next('/error')
  } finally {
    NProgress.done()
  }
})

```

### The Redirect Hack Explained

When redirecting inside `beforeEach`, always call `NProgress.done()` before or immediately after `next()` to avoid the bar lingering due to the aborted navigation:

```javascript
if (to.path === '/login' && hasToken()) {
  NProgress.done()
  next({ path: '/' })
}

```

This pattern prevents the progress bar from freezing at 90% when the router interrupts the current navigation to perform a redirect.

## Summary

- **File location:** All NProgress logic resides in [`src/permission.js`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/permission.js), lines 4‑74.
- **Lifecycle:** `NProgress.start()` fires in `router.beforeEach`; `NProgress.done()` fires manually on redirects/errors and automatically in `router.afterEach`.
- **Configuration:** The spinner is disabled via `NProgress.configure({ showSpinner: false })` to show only the top progress bar.
- **Error resilience:** Manual `done()` calls in catch blocks and redirect paths ensure the UI never remains stuck in a loading state.

## Frequently Asked Questions

### Where is the NProgress logic located in Vue-Element-Admin?

The NProgress integration is implemented entirely within [`src/permission.js`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/permission.js). This file registers the global `router.beforeEach` and `router.afterEach` hooks that control the progress bar lifecycle alongside authentication checks.

### Why is NProgress.done() called before next() on redirects?

Calling `NProgress.done()` before `next()` on redirects prevents the progress bar from hanging. When `next({ path: '/' })` interrupts the current navigation, the `router.afterEach` hook may not fire immediately, so manually completing the progress ensures the bar clears before the new route resolves.

### How do I customize the NProgress appearance in Vue-Element-Admin?

Modify the configuration object in [`src/permission.js`](https://github.com/PanJiaChen/vue-element-admin/blob/main/src/permission.js) (lines 6‑9). For example, enable the spinner and adjust animation speed:

```javascript
NProgress.configure({ showSpinner: true, speed: 400, trickleSpeed: 200 })

```

You can also override CSS classes defined in [`nprogress/nprogress.css`](https://github.com/PanJiaChen/vue-element-admin/blob/main/nprogress/nprogress.css) to change the bar color or height.

### Does NProgress work with async route guards?

Yes. The Vue-Element-Admin implementation specifically uses `async/await` inside `router.beforeEach` to fetch user information and permission routes. `NProgress.start()` runs immediately, providing visual feedback during the entire async resolution period until `done()` is called explicitly or via `router.afterEach`.