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:
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?
2) Visit the about page of the Vue app. /about
What do you see?
3) Visit a random url of the app. Like /hi/someurl/404
What do you see?
(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.
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!
And that's it! We have a fully functional 404 page now! Hope you enjoyed this tutorial!
Top comments (8)
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: "*"
withpath: "/:catchAll(.*)"
Thank you so much! 😀
You helped me a lot.
Now my 404 page is working.
Thanks for the solution!
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)
Great, Thank you