loading...
Cover image for Create a custom 404 page for your Vue 2 app

Create a custom 404 page for your Vue 2 app

khalby786 profile image Khaleel Gibran Updated on ・3 min read

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

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>

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

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
});

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

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!

Posted on by:

khalby786 profile

Khaleel Gibran

@khalby786

A "once thirteen", now fourteen y/o web developer who loves donuts, Node.js, Vue, Twitter and robots!

Discussion

pic
Editor guide
 

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

 

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!

 

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.

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(.*)"

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

Thanks for the solution!

 

Great, Thank you