Installing Unhead with Vue
Install @unhead/vue, create a head with createHead(), and register it through app.use(head). SSR uses separate client and server entry points with transformHtmlTemplate().
Unhead's Vue adapter originated in the @vueuse/head repository, which provided a Vue 3 successor to Vue Meta.
The examples follow Vite's SSR structure. A Vue SPA uses the same client entry.
Demos
Setup
1. Add Dependency
Install the @unhead/vue dependency in your project.
pnpm add @unhead/vue@nextVue 2
Unhead v2 and later do not support Vue 2. Vue 2 projects need @unhead/vue@^1.
pnpm add @unhead/vue@^1Then follow the v1 Vue installation guide.
Migrating from @vueuse/head
Follow the VueUse Head migration guide to remove the old package and update your imports.
2. Set Up Client-Side Rendering
Create the browser instance from @unhead/vue/client. In a Vite SSR app this usually belongs in entry-client.ts; in an SPA, put it in the main entry.
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')
3. Set Up Server-Side Rendering
For SSR, create a fresh instance from @unhead/vue/server for each request and return it with the rendered app.
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 }
}
After Vue renders, pass the instance and complete HTML template to transformHtmlTemplate():
import { transformHtmlTemplate } from '@unhead/vue/server'
// ...
// Serve HTML
app.use('*all', async (req, res) => {
try {
// ...
const rendered = await render(url)
const html = transformHtmlTemplate(
rendered.head,
template.replace(`<!--app-html-->`, rendered.html ?? '')
)
res.status(200).set({ 'Content-Type': 'text/html' }).send(html)
}
catch (e) {
// ...
}
})
// ..
4. Server Defaults
On the server, Unhead inserts these default tags:
<meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><html lang="en">
Set server-only defaults through init. Keeping them in the server entry also keeps them out of the 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' }
},
]
})
// ...
}
bodyAttrs can set attributes or inline styles on <body>:
<script setup lang="ts">
import { useHead } from '@unhead/vue'
useHead({
bodyAttrs: {
style: 'background: salmon; color: cyan;'
},
})
</script>
5. Enable Auto-Imports
unplugin-auto-import can provide the composables without explicit imports:
import { unheadVueComposablesImports } from '@unhead/vue'
import AutoImport from 'unplugin-auto-import/vite'
export default defineConfig({
plugins: [
AutoImport({
imports: [
unheadVueComposablesImports,
],
}),
// ...
]
})
Next Steps
Composables:
Optional integrations:
- Add support for the Options API
- Set up a
<Head>component - Add
useSchemaOrg()for structured data - Use
useScript()for loading triggers and script lifecycle hooks