unhead@betaQuick Start: Install @unhead/vue, create head with createHead(), and use app.use(head). For SSR, use separate client/server entry points with transformHtmlTemplate().
Unhead has first-class support for Vue. In fact much of the code belongs to the original @vueuse/head repo which was a Vue 3 version of Vue Meta.
Vue Unhead works both for CSR and SSR, and it's designed to be framework-agnostic, so you can use it with any Vue setup.
This guide assumes you're following a similar structure to the vite-ssr-vue template or a SPA Vue setup.
Install @unhead/vue dependency to your project.
pnpm add @unhead/vue@betaIn Unhead v2, official support for Vue 2 has been dropped. If you're using Vue 2, you will need to install v1 of @unhead/vue@^1 instead.
pnpm add @unhead/vue@^1To continue, please follow the v1 Unhead Vue installation.
To begin with, we'll import the function to initialize Unhead in our client Vue app from @unhead/vue/client.
In Vite this entry file is typically named entry-client.ts. If you're not server-side rendering, you can add this to your main Vue app entry instead.
import './style.css'
import { createApp } from './main'
import { createHead } from '@unhead/vue/client'
const { app } = createApp()
const head = createHead()
app.use(head)
app.mount('#app')
Setting up server-side rendering is more complicated as it requires rendering out the tags to the HTML string before sending it to the client.
We'll start with setting up the plugin in the server entry this time. Make sure to import from @unhead/vue/server instead
and add the head in the return object.
import { createHead } from '@unhead/vue/server'
import { renderToString } from 'vue/server-renderer'
import { createApp } from './main'
export async function render(_url: string) {
const { app } = createApp()
const head = createHead()
app.use(head)
const ctx = {}
const html = await renderToString(app, ctx)
return { html, head }
}
Now we need to render out the head tags after Vue has rendered the app.
Within your server.js file or wherever you're handling the template logic, you need to transform the template data
for the head tags using transformHtmlTemplate().
import { transformHtmlTemplate } from '@unhead/vue/server'
// ...
// Serve HTML
app.use('*all', async (req, res) => {
try {
// ...
const rendered = await render(url)
const html = await transformHtmlTemplate(
rendered.head,
template.replace(`<!--app-html-->`, rendered.html ?? '')
)
res.status(200).set({ 'Content-Type': 'text/html' }).send(html)
}
catch (e) {
// ...
}
})
// ..
Done! Your app should now be rendering head tags on the server and client.
To improve your apps stability, Unhead will now insert important default tags for you.
<meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><html lang="en">You may need to change these for your app requirements, for example you may want to change the default language. Adding tags in your server entry means you won't add any weight to your client bundle.
import { createHead } from '@unhead/vue/server'
export async function render(_url: string) {
// ...
const head = createHead({
init: [
// change default initial lang
{
title: 'Default title',
titleTemplate: '%s | My Site',
htmlAttrs: { lang: 'fr' }
},
]
})
// ...
}
Feel free to play around with adding tags to your apps. Here's an example of adding some styles to the body.
<script setup lang="ts">
import { useHead } from '@unhead/vue'
useHead({
bodyAttrs: {
style: 'background: salmon; color: cyan;'
},
})
</script>
If you're using unplugin-auto-import, you can automatically import the composables.
import { unheadVueComposablesImports } from '@unhead/vue'
import AutoImport from 'unplugin-auto-import/vite'
export default defineConfig({
plugins: [
AutoImport({
imports: [
unheadVueComposablesImports,
],
}),
// ...
]
})
Your Vue app is now setup for head management, congrats! 🎉
You can get started with any of the composables:
Or explore some of the optional extras:
<Head> componentuseSchemaOrg() for structured datauseScript() for performance optimized script loading