To set the document title, we define the <title> tag in our index.html file:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vue Tip: Dynamically Change Page Title</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
In many applications, we have different routes and want to show a dedicated title for each route.
Unfortunately, this does not work out of the box, and we need to write some code to enable this functionality.
Let's take a look at an exemplary route configuration (check the Vue Router docs for more details about Vue Router):
import { createRouter, createWebHistory } from 'vue-router'
import Home from '@/views/Home.vue'
const router = createRouter({
history: createWebHistory(),
routes: [
{
path: '/',
component: Home,
},
{
path: '/about',
component: () => import('@/views/About.vue'),
},
{
path: '/contact',
component: () => import('@/views/Contact.vue'),
},
],
})
export default router
We can use the beforeEach guard on the router instance to dynamically set the document title on each route. The beforeEach guard adds a navigation guard that executes before any navigation:
router.beforeEach((to, from) => {
document.title = to.meta?.title ?? 'Default Title'
})
Inside the navigation guard callback, we use document.title to set the document's title. We use the nullish coalescing operator (??) in combination with optional chaining (?.) to set Default Title if the meta object or the title is undefined.
Finally, we need to define the metadata on our routes:
routes: [
{
path: '/',
component: Home,
meta: {
title: 'Home',
},
},
{
path: '/about',
component: () => import('@/views/About.vue'),
meta: {
title: 'About',
},
},
{
path: '/contact',
component: () => import('@/views/Contact.vue'),
meta: {
title: 'Contact',
},
},
],
At this point, we have updated our code to dynamically update the page title when the page changes. The following StackBlitz playground contains a running example:
We can improve the code by adding "more dynamic" page titles using route props:
<script setup>
const client = await useClient()
</script>
<template>
<router-link :to="{ name: 'ViewClient', params: { pageTitle: `${client.firstName} ${client.lastName}` } }">
View client details
</router-link>
</template>
We can access the route params via to.params and set the document's title accordingly:
router.beforeEach((to, from, next) => {
const titleFromParams = to.params?.pageTitle
if (titleFromParams) {
document.title = `${titleFromParams} - ${document.title}`
} else {
document.title = to.meta?.title ?? 'Default Title'
}
})
If you liked this Vue tip, follow me on BlueSky to get notified about new tips, blog posts, and more. Alternatively (or additionally), you can subscribe to my weekly Vue & Nuxt newsletter :

