Tutorial

How To Change Metadata in Vue.js with vue-meta

Vue.js

Introduction

The vue-meta library provides a Vue plugin that allows you to take control of your application’s metadata from a component level.

It is important to curate the metadata of your web apps for search engine optimization (SEO), but when working with single-page web applications (SPAs) this can often be a cumbersome task. Dynamic metadata was already partially covered in this vue-router tutorial.

In this article, you will explore how the vue-meta plugin handles this for you in a concise, logical way while providing you with even more control over your application’s metadata.

Prerequisites

If you would like to follow along with this article, you will need:

This tutorial was verified with Node v15.8.0, npm v7.5.4, Vue v12.6.11, and vue-meta v2.4.0.

Using vue-meta

First, to use vue-meta, open your terminal and navigate to your existing Vue project directory. Then, run the following command:

  • npm install vue-meta@2.4.0

Next, with your code editor, open the main.js file and bootstrap the plugin:

src/main.js
import Vue from 'vue'
import VueMeta from 'vue-meta'
import App from 'App.vue'

Vue.use(VueMeta)

new Vue({
  render: h => h(App),
}).$mount('#app')

Save your changes and then vue-meta will be available to your application.

Integrating with Vue Router

If you are using a routing solution like vue-router, then you could bootstrap vue-meta in your router/index.js file:

src/router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import VueMeta from 'vue-meta'

Vue.use(Router)
Vue.use(VueMeta)

export default new Router({})

Save your changes and then vue-meta and vue-router will be available to your application.

Integrating with Server Side Rendering

If you are using Server Side Rendering (SSR) you will want to bootstrap vue-meta in a file that runs on both the server and the client before the root Vue instance is mounted.

Integrating with Vue Frameworks

If you are using a framework that already uses vue-meta, such as NuxtJS, you will not need to bootstrap. Instead, you should refer to the documentation for your chosen framework.

Other frameworks that already use vue-meta include Gridsome, Ream, Vue-Storefront, and Factor JS.

Customizing Plugin Options

vue-meta provides options to customize the plugin’s behavior. NuxtJS takes advantage of this by changing the name of the “metaInfo” property to “head”.

You can replicate this by bootstrapping vue-meta with a keyName:

src/main.js
import Vue from 'vue'
import VueMeta from 'vue-meta'
import App from 'App.vue'

Vue.use(VueMeta, {
  keyName: 'head'
})

new Vue({
  el: '#app',
  render: h => h(App)
})

Make sure to check out the full list of options available in the official documentation.

Populating Metadata

vue-meta allows you to update the <title> tag on both parent and child components. In your root component, you can define a default title that will appear if a child component lacks one. You can also define a titleTemplate which will be used to display the title from child components.

src/App.vue
export default {
  name: 'App',
  metaInfo: {
    title: 'Default App Title',
    titleTemplate: '%s | vue-meta Example App'
  },
  // ...
}

This titleTemplate will produce the following <title>:

Output
<title> Default App Title | vue-meta Example App </title>

Often you want to include other information to pass to the browser or web crawler such as a page’s charset, description, or viewport. You can even add attributes to the page’s html and head tags. And also inject external scripts.

src/App.vue
export default {
  name: 'App',
  metaInfo: {
    title: 'Default App Title',
    titleTemplate: '%s | vue-meta Example App',
    htmlAttrs: {
      lang: 'en-US'
    },
    meta: [
      { charset: 'utf-8' },
      { name: 'description', content: 'An example Vue application with vue-meta.' },
      { name: 'viewport', content: 'width=device-width, initial-scale=1' }
    ]
  },
  // ...
}

This code will generate the following output:

Output
<html lang="en-US"> <head> <title>Default App Title | vue-meta Example App</title> <meta charset="utf-8"> <meta name="description" content="'An example Vue application with vue-meta."> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> </html>

Make sure to check out the metaInfo properties spec of the vue-meta API documentation for all of the options available.

Understanding metaInfo Behavior for Parent and Child Components

Child components will recursively merge metadata with their parents. This allows us to update the page’s metadata based on which components are currently mounted.

The App component is a parent component with title and titleTemplate defined:

src/App.vue
<template>
  <div>
    <HelloWorld />
  </div>
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'

export default {
  name: 'App',
  metaInfo: {
    title: 'Default App Title',
    titleTemplate: '%s | vue-meta Example App'
  },
  components: {
    HelloWorld
  }
}
</script>

The HelloWorld component is a child component of the App component with a title defined:

src/components/HelloWorld.vue
<template>
  <div>Hello World!</div>
</template>

<script>
export default {
  name: 'HelloWorld',
  metaInfo: {
    title: 'Hello World!'
  }
}
</script>

This code will generate the following output:

Output
<title> Hello World! | vue-meta Example App </title>

The child component’s title overrides the parent’s title.

You could also disable the titleTemplate from a child component like so:

src/components/HelloWorld.vue
export default {
  name: 'HelloWorld',
  metaInfo: {
    title: 'Hello World!',
    titleTemplate: null
  }
}

This code will generate the following output:

Output
<title> Hello World! </title>

If two child components are mounted and both contain metaInfo, the last child to be mounted will be used to populate the page’s metadata.

Suppose you created a second child component called HelloWorld2. Modify the App component like the previous example as below:

src/App.vue
<template>
  <div>
    <HelloWorld />
    <HelloWorld2 />
  </div>
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'
import HelloWorld2 from './components/HelloWorld2.vue'

export default {
  name: 'App',
  metaInfo: {
    title: 'Default App Title',
    titleTemplate: '%s | vue-meta Example App'
  },
  components: {
    HelloWorld,
    HelloWorld2
  }
}
</script>

The HelloWorld2 component is a child component of the App component with a title defined - different from the title defined in the HelloWorld component:

src/components/HelloWorld2.vue
<template>
  <div>Hello World 2!</div>
</template>

<script>
export default {
  name: 'HelloWorld2',
  metaInfo: {
    title: 'Hello World 2!'
  }
}
</script>

This code will generate the following output:

Output
<title> Hello World 2! | vue-meta Example App </title>

Using multiple Vue instances with vue-meta will result in only the metadata from the last app to be updated!

Only duplicate metadata will be overwritten by child components. Other metadata will be concatenated.

Enforcing Unique metaInfo Behavior with vmid

vue-meta allows you to assign a special property called vmid to your metaInfo so that you can control how it resolves with your component tree.

If two sets of metadata have the same vmid, such as a parent and child, they will not merge but instead, the child will override the parent.

Here is an example of a parent component with a vmid of “description” and a content of “Parent description”:

Parent Component
{ metaInfo: { meta: [ { charset: 'utf-8' }, { vmid: 'description', name: 'description', content: 'Parent description.' } ] } }

And here is an example of a child component with an identical vmid of “description” and a different content of “Child description”:

Child Component
{ metaInfo: { meta: [ { vmid: 'description', name: 'description', content: 'Child description.' } ] } }

This code will generate the following output:

Output
<meta charset="utf-8"> <meta data-vmid="description" name="description" content="Child description.">

If a child component shares a vmid with a parent and a metaInfo property is set to null, this property will be removed from the parent.

If a child component returns undefined for a metaInfo property vue-meta will fall back to the parent’s property.

Conclusion

vue-meta is a great solution if you’re looking to take control of and dynamically update your app’s metadata.

Make sure to review the official documentation if you’d like to learn more about all the library has to offer.

If you’d like to learn more about Vue.js, check out our Vue.js topic page for exercises and programming projects.

Creative Commons License