@vueuse/head

Reactive document head and meta tag manager for Vue 3, built as a legacy-compatible wrapper around Unhead.

Library
npm
v2.0.0
950stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
48/100Fair
Development Activity0
Maintenance48
Community44
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
61/100Good
Architecture65
Code Quality68
Innovation55
Learning Curve55

@vueuse/head lets Vue 3 (and Vue 2.7+) applications manage the document <title>, meta tags, link tags, and other head elements reactively, with full SSR support so head state resolves correctly on the server before hydration. It exposes the original push()-based imperative API and a Vue 2 plugin that predate the Unhead project, while internally delegating all tag resolution, deduplication, and rendering to @unhead/vue and @unhead/ssr.

The package is now sunset: its maintainers have folded all further development into Unhead directly and only ship bug fixes and security patches here. Existing consumers get a stable, backward-compatible surface without a rewrite, but new projects are pointed at @unhead/vue, which exposes the same composables (useHead, useSeoMeta, useServerHead) without the legacy adapter layer.

What You Get

  • createHead() factory that wraps Unhead’s client in a legacy-shaped object exposing push(), headEntries(), and resolveTags()
  • Re-exported Unhead composables — useHead, useSeoMeta, useServerHead, useHeadSafe, injectHead — for apps ready to adopt the newer API surface
  • A <Head> component for declarative, template-based head management alongside the imperative API
  • HeadVuePlugin and renderHeadToString helpers for Vue 2 SSR integration and server-side head string rendering
  • TypeScript types (MergeHead, ReactiveHead, HeadTag, ActiveHeadEntry) shared with the underlying Unhead schema

Common Use Cases

  • Setting per-page <title> and meta description tags in a Vue 3 SPA or SSR app for SEO
  • Injecting Open Graph and social-card meta tags reactively based on route or fetched data
  • Server-rendering head tags in a custom Vite SSR setup via renderHeadToString before sending HTML to the client
  • Maintaining a legacy Vue 2 codebase’s existing @vueuse/head integration without migrating to @unhead/vue immediately

Under The Hood

Architecture The package is a facade/adapter layer, not an independent implementation: createHead.ts calls @unhead/vue’s createHead() to build a real Unhead client, then wraps it with polyfillAsVueUseHead() to restore the original imperative push() API vueuse/head consumers expect; legacy.ts separately re-exports a Vue 2 provide plugin (HeadVuePlugin) and an SSR string-renderer (renderHeadToString) that simply calls @unhead/ssr’s renderSSRHead; components/Head.ts re-exports Unhead’s <Head> component unchanged; and index.ts aggregates everything, including direct re-exports of Unhead’s newer composables (useHead, useSeoMeta, injectHead). Every piece of real logic — tag merging, deduplication, priority resolution, SSR serialization — lives in @unhead/vue and @unhead/ssr; this package’s only job is preserving a pre-Unhead API shape during migration.

Tech Stack TypeScript throughout, built with unbuild per build.config.ts, and built on four @unhead/* packages (dom, schema, ssr, vue) as its only runtime dependencies, with vue declared as a peer dependency covering both Vue 2.7+ and Vue 3. Tests run under vitest with inline snapshots, plus a Nuxt-based integration pass via @nuxt/test-utils and an end-to-end Playwright/Vite SSR example. Linting follows @antfu/eslint-config, dependencies are managed with pnpm, and GitHub Actions (test.yml) runs the full test suite on every push and PR to main.

Code Quality Test coverage is extensive relative to the package’s small surface area — over 2,300 lines across dedicated suites for deduplication, tag priority, title templating, character encoding, Vue SSR rendering, reactivity typing, and backwards-compatibility with the original head-object shape. Source files are short and single-purpose, but several touch points into @unhead/vue’s internals (the polyfill and <Head> component re-exports) are marked with @ts-expect-error broken types, showing known type-safety gaps at the compatibility boundary rather than in the package’s own logic. Error handling is minimal by design since almost all behavior is delegated upstream.

What Makes It Unique The package doesn’t introduce new document-head mechanics — that innovation belongs to Unhead itself. Its actual contribution is a migration bridge: Vue applications written against the original imperative @vueuse/head API (push(), the Vue 2 plugin, renderHeadToString) can adopt Unhead’s newer engine underneath without touching call sites, while the README actively steers new adoption toward @unhead/vue directly. That makes this package a deliberately transitional compatibility layer rather than a piece of ongoing feature development.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search