DEV Community

Cover image for Create a custom 404 page for your Vue 2 app
Khaleel Gibran
Khaleel Gibran

Posted on • Updated on

Create a custom 404 page for your Vue 2 app

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

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:

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
Enter fullscreen mode Exit fullscreen mode

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

What do you see?

Vue app homepage

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

What do you see?

Vue app about

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

What do you see?

Vue app homepage

(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 😅)

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

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.

<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>
Enter fullscreen mode Exit fullscreen mode

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

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

Enter fullscreen mode Exit fullscreen mode

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.

const router = new VueRouter({
  mode: 'history',
  routes
});
Enter fullscreen mode Exit fullscreen mode

The final src/router/index.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
Enter fullscreen mode Exit fullscreen mode

And now, our URL looks normal!

Vue Normal URL

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

Discussion (8)

Collapse
mccrush profile image
Sergey Nikolaev

Great article. But why doesn't this work with Vue 3.0?

Collapse
khalby786 profile image
Khaleel Gibran Author • Edited

Are you getting any errors of any sort (in the DevTools)?

Also, github.com/khalby786/personal-website is where I have implemented this and it works fine!

Collapse
mccrush profile image
Sergey Nikolaev

Errors in console: «Error: A non-empty path must start with "/"»

The way you mentioned works with Vue 2.*, but doesn't work with Vue 3.0.
And I cannot understand why ...

But thanks.
I'll ask on Github, maybe they will tell me there.

Thread Thread
amravazzi profile image
André Ravazzi

I think this will solve your problem: github.com/vuejs/vue-router-next#b...

TL;DR: You will need to replace path: "*" with path: "/:catchAll(.*)"

Thread Thread
mccrush profile image
Sergey Nikolaev

Thank you so much! 😀
You helped me a lot.
Now my 404 page is working.

Thread Thread
khalby786 profile image
Khaleel Gibran Author

Thanks for the solution!

Collapse
katmedinah profile image
Kat Medinah (codename)

Hi Khaleel, thanks for the post. Unrelated question: Is there any way to serve a custom “Page not found” 404 page in a Vue.js MPA (multipage application) by modifying vue.config.js? (I am not using vue-router)

Collapse
jaimebboyjt profile image
Jaimebboyjt

Great, Thank you