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.
If you would like to follow along with this article, you will need:
<head>
, <title>
,<meta>
.This tutorial was verified with Node v15.8.0, npm
v7.5.4, Vue v12.6.11, and vue-meta
v2.4.0.
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:
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.
If you are using a routing solution like vue-router
, then you could bootstrap vue-meta
in your router/index.js
file:
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.
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.
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.
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
:
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.
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.
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.
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.
metaInfo
Behavior for Parent and Child ComponentsChild 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:
<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:
<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:
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:
<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:
<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.
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.
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.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!