Create a custom 404 page for your Vue 2 app
Tags: tutorial, vue
Published: 2020-08-02 11:01:42

In this tutorial, you'll learn how to add a custom 404 page to a Vue app (generated using the Vue CLI) with a basic Vue router configuration.

For this tutorial, I will be using a Vue router starter app generated using the Vue CLI. Here's how the project file tree might look:

![Vue CLI Router Filetree](https://dev-to-uploads.s3.amazonaws.com/i/mkpk9ud7lzdyxndtn4nn.png)

Right now, all we need to focus on are `src/router/index.js` and the components of the `src/views` folder. 

This is how `src/router/index.js` should somewhat look:

```js
import Vue from 'vue';
import VueRouter from 'vue-router';
import Home from '../views/Home.vue';
import About from '../views/About.vue';

Vue.use(VueRouter)

  const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/about',
    name: 'About',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
  }
]

const router = new VueRouter({
  routes
})

export default router
```

1) Visit the home page of the Vue app. `/`

*What do you see?*

![Vue app homepage](https://dev-to-uploads.s3.amazonaws.com/i/pn0k2mbfka2ptbf6rio7.png)

2) Visit the about page of the Vue app. `/about`

*What do you see?*

![Vue app about](https://dev-to-uploads.s3.amazonaws.com/i/q87gglgxito3465vy93v.png)

3) Visit a random url of the app. Like `/hi/someurl/404`

*What do you see?*

![Vue app homepage](https://dev-to-uploads.s3.amazonaws.com/i/xd5qop6vpqrmf7lj1sjr.png)

(**I customised my Vue app a lot, so it looks a whole lot different from the starter Vue router app, kindly excuse me for that :sweat_smile:**)

*What do we notice from the above 3 scenarios?*

If we visit a URL that exists, it correctly renders the component associated with that route. But if the URL does not exist, it just redirects it to the homepage, instead of showing some sort of error or a default 404 page. You might also have noticed that the URL of the default Vue app has `/#/` suffixed to the URL.

![Vue app URL](https://dev-to-uploads.s3.amazonaws.com/i/kncbrly9nbg3zcxhuvzy.png)

We can fix all of these issues.

For the redirecting-to-homepage-when-it-doesn't-exist case, we can create a custom 404 page, by specifying a wildcard route after **all** the other routes. First, we will have to create a 404 component.

In `src/views` folder, create a file named `NotFound.vue`. Add some basic text and images that makes it look like a 404 page. 

```vue
<template>
  <center>
    <h1>Not Found!</h1>
    <p>
      <a href="/">Go home?</a>
    </p>
  </center>
</template>

<script>
  
  export default {
    name: 'NotFound'
  }
  
</script>

<style scoped>
  
  center {
    margin: 15vw;
  }
  
  h1 {
    color: var(--border);
    font-size: 2em;
  }
  
</style>
``` 

Once you have created `NotFound.vue`, in `src/router/index.js` add a wildcard route pointing towards the `NotFound.vue` component.

```js
import Vue from 'vue';
import VueRouter from 'vue-router';
import Home from '../views/Home.vue';
import About from '../views/About.vue';
import NotFound from '../views/NotFound.vue';

Vue.use(VueRouter)

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/about',
    name: 'About',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
  },
  {
    path: '*',
    name: 'Not Found',
    component: NotFound
  }
]

const router = new VueRouter({
  routes
})

export default router

```

But we need to do one more thing, only then can we "successfully" create a 404 page.

**The weird URL**.

The "weird" URL is because the Vue router uses *hash mode* for routing by default. It uses the URL hash to simulate a full URL so that the page won't be reloaded when the URL changes.

We can prevent the Vue router from doing this by enabling *History* mode. 

```js
const router = new VueRouter({
  mode: 'history',
  routes
});
```

The final `src/router/index.js`:

```js
import Vue from 'vue';
import VueRouter from 'vue-router';
import Home from '../views/Home.vue';
import About from '../views/About.vue';
import NotFound from '../views/NotFound.vue';

Vue.use(VueRouter)

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/about',
    name: 'About',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
  },
  {
    path: '*',
    name: 'Not Found',
    component: NotFound
  }
]

const router = new VueRouter({
  mode: 'history',
  routes
})

export default router
```

And now, our URL looks normal!

![Vue Normal URL](https://dev-to-uploads.s3.amazonaws.com/i/wcju4wzfq150i8vqxl3n.png)

And that's it! We have a fully functional 404 page now! Hope you enjoyed this tutorial!