unhead-vue-skilld

v2026.09.25

Full-stack <head> manager for Vue (@unhead/vue 3.x). Use when writing, reviewing, or debugging code that imports @unhead/vue, calls useHead, useSeoMeta, useHeadSafe, useScript, injectHead, createHead, or sets up Unhead SSR / streaming SSR / build plugins in a Vue app.

GitHub
Install command
npx skhub add skilld-dev/unhead-vue-skilld
Markdown
SKILL.md

@unhead/vue 3.4.1

Full-stack <head> management for Vue 3. ESM only ("type": "module"), no CJS. Peer deps: vue >= 3.5.18; optional vite >= 6.4.2, webpack >= 5.0.0 (source: package.json:138-150). Vue 2: not supported; use @unhead/vue@^1. Nuxt: Unhead is integrated already; do not install or set it up manually.

Setup (mandatory)

Install @unhead/vue, create the head instance, and register it as a Vue plugin. createHead comes from a subpath export, not the package root.

// entry-client.ts (SPA or hydration)
import { createHead } from '@unhead/vue/client'
import { createApp } from './main'

const { app } = createApp()
const head = createHead()
app.use(head)
app.mount('#app')
// entry-server.ts (SSR)
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 html = await renderToString(app)
  return { html, head } // render tags later with transformHtmlTemplate(head, template)
}

Full SSR template wiring, streaming SSR, Options API, and auto-imports: references/setup.md.

Composables

All imported from @unhead/vue root and used inside setup():

<script setup lang="ts">
import { useHead, useSeoMeta } from '@unhead/vue'

useHead({
  title: () => `${user.value.name} - Profile`, // getters, refs, computed all reactive
  titleTemplate: '%s | My Site',
  meta: [{ name: 'description', content: () => description.value }],
})

useSeoMeta({ // flat, type-safe keys; og/twitter handled automatically
  ogTitle: 'My Page',
  ogImage: 'https://example.com/image.jpg',
})
</script>
// Third-party scripts
import { useScript } from '@unhead/vue'

const { proxy, onLoaded, status } = useScript(
  { src: 'https://example.com/analytics.js' },
  { use: () => window.analytics, trigger: 'client' },
)
proxy.track('pageview') // queued until the script loads

Details, options tables, and recipes: references/composables.md.

Critical rules

  1. Async context: calling useHead() after an await inside onMounted()/watchers throws useHead() was called without provide context. Fix, in order of preference: top-level await in <script setup>; declare useHead() once with refs/computed and update the ref later; capture const head = injectHead() at setup time and pass useHead(input, { head }). Source: https://unhead.unjs.io/docs/vue/head/guides/core-concepts/reactivity-and-context
  2. Never call useHead() inside a watcher callback: each call pushes a new entry and duplicates tags. Pass the reactive value into one useHead() call instead.
  3. Deduplication key is key, not hid/vmid: meta: [{ key: 'description', name: 'description', content: '...' }].
  4. Inline content: innerHTML (was children in v1); body scripts use tagPosition: 'bodyClose' (was body: true).
  5. Untrusted input: use useHeadSafe(); it whitelists attributes and strips scripts/handlers.
  6. Head instance access in Vue: use injectHead() from @unhead/vue, not getActiveHead() from unhead; only the former binds to component context (e.g. onServerPrefetch).

Deprecated in 3.4.1 (present but slated for removal)

ExportStatusReplacement
useServerHead, useServerHeadSafe, useServerSeoMetadeprecated (dist/index.d.ts:26-30)useHead / useHeadSafe / useSeoMeta
@unhead/vue/legacy (createHead, createServerHead, legacyPlugins)deprecated, removed in v4 (dist/legacy.d.ts:14-30)@unhead/vue/client / @unhead/vue/server
resolveUnrefHeadInputdeprecated (dist/utils.d.ts:9)resolveTags(head) from unhead/utils
unheadVuePlugin from @unhead/vue/stream/vitedeprecated (dist/stream/vite.d.ts:8)Unhead({ streaming: true }).vite() from @unhead/vue/bundler
MergeHead typedeprecated (dist/types.d.ts:66)generics on VueHeadClient

Removed in v3 (will not compile): DeprecationsPlugin, setHeadInjectionHandler, createHeadCore, { mode: 'server' | 'client' } entry option, init/dom:renderTag/dom:rendered hooks, headEntries() (use [...head.entries.values()]). Migration details: references/migration.md.

Export map

SubpathPurpose
@unhead/vuecomposables: useHead, useSeoMeta, useHeadSafe, useScript, injectHead, VueHeadMixin, unheadVueComposablesImports, createUnhead, defineLink, defineScript
@unhead/vue/clientcreateHead() (SPA/hydration), renderDOMHead, VueHeadMixin
@unhead/vue/servercreateHead() (SSR), renderSSRHead, transformHtmlTemplate, propsToString
@unhead/vue/components<Head> component
@unhead/vue/pluginsre-exports unhead/plugins (TemplateParamsPlugin, AliasSortingPlugin, PromisePlugin, InferSeoMetaPlugin, ValidatePlugin, ...)
@unhead/vue/bundlerunified build plugin Unhead() for vite/webpack/rspack/rollup
@unhead/vue/viteVite-only Unhead(); prefer /bundler
@unhead/vue/stream/server, /stream/clientcreateStreamableHead() for streaming SSR
@unhead/vue/types, /utils, /scripts, /legacytypes, utilities, script types, legacy shims

Signatures and full type surface: references/api-surface.md.

Optional plugins at creation

Template params (%s, %separator), alias sorting (before:/after:), and Promise inputs are opt-in since v2:

import { createHead } from '@unhead/vue/client'
import { AliasSortingPlugin, TemplateParamsPlugin } from '@unhead/vue/plugins'

const head = createHead({ plugins: [TemplateParamsPlugin, AliasSortingPlugin] })

Without TemplateParamsPlugin, %siteName placeholders render literally.

Build plugin (recommended for standalone Vue apps)

// vite.config.ts
import { Unhead } from '@unhead/vue/bundler'

export default defineConfig({
  plugins: [vue(), Unhead()], // add { streaming: true } for streaming SSR
})

Tree-shakes server-only composables from the client bundle, converts useSeoMeta() to useHead() (~3kb), injects ValidatePlugin in dev. Options table and webpack notes: references/build-plugins.md.

Common mistakes

  • Importing createHead from @unhead/vue root (removed in v2): use /client or /server.
  • Awaiting renderSSRHead / renderDOMHead: both are synchronous in v3.
  • useScript() return is not a Promise: use onLoaded(() => ...); call APIs through .proxy.
  • Meta tags require content: { name: 'description', content: null } removes the tag.
  • Font preloads require crossorigin: { rel: 'preload', as: 'font', href: '/f.woff2', crossorigin: 'anonymous' }.

References

Discovery
Tags

No tags published for this skill.

Version
Latest version metadata

Version

v2026.09.25

Published

Sep 25, 2026

Category

Uncategorized

License

MIT

Source path

skills/unhead-vue-skilld

Default branch

main

Latest commit

c8994af

Tree SHA

78224cb