A simple way to keep your Vue page title in sync with the router
Karolis

Karolis @krusenas

About: Principal Engineer @ Lightning.AI, maker of Webhook Relay, Synpse, Meteron Projects: - webhookrelay.com - keel.sh

Location:
London
Joined:
Nov 1, 2018

A simple way to keep your Vue page title in sync with the router

Publish Date: Sep 8 '19
133 8

I have noticed in quite a few projects that developers forget to keep page title updated with the router or maybe think that they will do it tomorrow as it is such a small feature :). It always makes sense to keep the title synchronized with the contents for several reasons:

  • helps users with more than one tab
  • important for website analytics

I will show you how to do it with the standard vue-router.

Step 1: Declare route meta in your router config

First things first, let's add some additional metadata to our standard routes:

  routes: [
    {
      path: '/',
      name: 'home',
      component: HomePage,
      meta: {
        auth: true,
        title: 'Dashboard'
      }
    }, {
      path: '/login',
      name: 'login',
      component: LoginPage,
      meta: {
        auth: false,
        title: 'Login'
      }
    }, {
      path: '/buckets',
      name: 'buckets',
      component: BucketsPage,
      meta: { auth: true, title: 'Buckets' }
Enter fullscreen mode Exit fullscreen mode

More docs on the router package can be found in the official vue router website.

Step 2: Add $route watcher in your App.vue

Go to your Vue main .vue file (it should have a <router-view></router-view> component) and add a watcher:

    watch: {
      '$route' (to, from) {
        document.title = to.meta.title || 'Your Website'
      }
    },

Enter fullscreen mode Exit fullscreen mode

This will set a title as your page title (if you specified a meta field for that route). I have tried to achieve the same with router navigation guards but $route watcher seemed like the simplest solution.

Looks easy, right? :) Feel free to experiment and define more fields in the router meta like page description and anything else you want to be set for that page. Then modify the watcher to also use them.

Hope this helps!

Comments 8 total

  • Loftie Ellis
    Loftie EllisSep 9, 2019

    Updating the title is definetly something a lot of spa's seems to neglect.
    In your example you should probably specify immediate:true for the watch, otherwise the title wont update on the first load

    watch: {
          '$route':{
            handler: (to, from) => {
              document.title = to.meta.title || 'Your Website'
            },
             immediate: true
          }
        },
    
    Enter fullscreen mode Exit fullscreen mode

    And if you start adding more metadata I would recommend looking at github.com/nuxt/vue-meta

  • Derek D
    Derek DSep 10, 2019

    Navigation guard inside your router makes more sense structurally IMO, but each work well:

    router.beforeEach((to, from, next) => {
      document.title = to.meta.title || 'Your Website Title');
      next();
    });
    
    Enter fullscreen mode Exit fullscreen mode

    ;)

  • Simon Measures
    Simon MeasuresSep 10, 2019

    I'm wondering why you have Step 2 with the title "Add $route watcher in your App.vue" but then the tutorial text instructs us to put the watcher in main.vue. Could you please clarify this.

    • Karolis
      KarolisSep 10, 2019

      By main vue file I meant the file that contains the router view inside it. Some template generators that I used would name it App.vue :)

  • Snehanshu Phukon
    Snehanshu PhukonJan 18, 2020

    Another way is using router.afterEach

    router.afterEach((to, from) => {
      if (to.meta && to.meta.title) {
        document.title = to.meta.title + ' | Any suffix';
      }
    });
    
    Enter fullscreen mode Exit fullscreen mode
  • alin
    alinJan 3, 2021

    Thanks so much!

  • AkifObaidi
    AkifObaidiFeb 22, 2021

    Thanks so Much.

  • Alex Lab
    Alex LabAug 16, 2021

    Hello, here is a version with the composition API:

    <script lang="ts">
    import { defineComponent, watch } from 'vue';
    import { useRoute } from 'vue-router';
    
    export default defineComponent({
      setup() {
        const route = useRoute();
    
        watch(
          () => route.meta.title,
          () => {
            document.title = route.meta.title as string;
          }
        );
      },
    });
    </script>
    
    Enter fullscreen mode Exit fullscreen mode
Add comment