The full stack <head> package for any framework.

Unhead wraps your document template, improving reactive SSR JavaScript framework SEO and performance.

Simply useHead()

Unhead prefers a minimal API surface with most of the functionaltiy provided through the useHead() hook.

✅ Titles that just work

useHead({
  title: 'Hello World',
  titleTemplate: '%s %separator My App',
})
// Hello World - My App

✅ DOM Events

useHead({
  script: [{
    src: '/script.js',
    onload: () => alert('woo'),
  }],
})

✅ Classes and styles however you like

useHead({
  bodyAttrs: {
    // use strings
    style: 'background-color: #343434',
    // arrays
    class: ['dark', 'overflow'],
  },
  htmlAttrs: {
    // objects
    style: {
      backgroundColor: 'white',
      color: 'black',
    },
    // computed boolean objects
    class: {
      dark: () => Date.now() % 2 === 0,
    },
  },
})

Side Effect DOM Updates

All side effects are tracked so that unmounting a component will revert its head modifications and reactive updates can be made at any time.
Modal.vue
<script lang="ts" setup>
useHead({
  title: 'Subscribe now!',
  htmlAttrs: {
    class: { dark: true, light: false }
  },
  bodyAttrs: { 
    style: { overflow: 'hidden' },
    'data-modal': true,
  },
  link: [{
    rel: 'preload',
    href: 'https://3p.com/subscribe.js',
    as: 'script',
  }],
})
</script>
<!DOCTYPE html>
<html class="light">
<head>
<title>Hello World</title>
</head>
<body>
<!-- Your app -->
</body>
</html>
Component Not Mounted

Optimized SEO Tags

Nail your SEO with foolproof flat meta config and the simplest Schema.org you've ever worked with.

Flat SEO Meta

Was it <meta property or <meta name? Who can remember, just use useSeoMeta().

useSeoMeta({
  ogType: 'article',
  author: 'Harlan Wilton',
  articleAuthor: ['Harlan Wilton'],
  articlePublishedTime: '2024-01-01',
  articleModifiedTime: '2024-01-01',
  twitterData1: 'Harlan Wilton',
  twitterLabel1: 'Author',
  twitterData2: '10 min',
  twitterLabel2: 'Read Time',
})

Schema.org Graphs

Rich result optimized Schema.org graphs without the <script type="application/ld+json>.

useSchemaOrg([
  definePerson({
    name: 'Harlan Wilton',
    sameAs: [
      'https://github.com/harlan-zw',
    ],
    url: 'https://harlanzw.com',
  }),
  defineArticle({
    headline: 'Hello World',
    datePublished: '2024-01-01',
  }),
])

Making Websites Faster

Unhead ships to be tree shaken with client and server export paths.

Optimized Head tag ordering

Unhead ships with a default head tag order that is optimized for SEO and performance.

<head>
<script defer src="defer-script.js"></script>
<script src="sync-script.js"></script>
<style>.sync-style { color: red }</style>
<link rel="modulepreload" href="modulepreload.js">
<script src="async-script.js" async></script>
<link rel="preload" href="preload.js">
<link rel="stylesheet" href="sync-styles.css">
<title>title</title>
<link rel="preconnect" href="https://example.com">
<link rel="dns-prefetch" href="https://example.com">
<link rel="prefetch" href="https://example.com">
<link rel="prerender" href="https://example.com">
<meta name="description" content="description">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>

A <script> for full stack javascript

Better developer experience, performance and privacy.

const script = useScript({
  src: 'https://js.cdn/tracker.js',
}, {
  trigger: useOnIdle()
})
script.onError((error) => { /* uh oh */ })
// proxy function calls for when the script is loaded
script.proxy.track('foo')
// or just use onLoaded
script.onLoaded((api) => {
  api.track('bar')
})

✅ Optimized Client Bundles

// gets removed from the client build
useServerHead({
  script: [{
    innerHTML: 'console.log("Hello World")',
  }],
})

Unhead Principals

Full Featured Developer Experience

Full featured modules that do everything you expect and more.

Minimal client build: 6.7kb gz

Optional utils are tree shakable, keeping a small core and allowing for a minimal bundle size.

Extensible

Internally powered by hookable to allow for full customisatin over output.

Up To Date. Always.

Unhead was started at the end of 2022 and has received continuous bug fixes and feature improvements from the community.

GitHub User harlan-zwGitHub User dargmuesliGitHub User huang-julienGitHub User 719mediaGitHub User s-en-oGitHub User vetruvetGitHub User LittleSoundGitHub User mittalyashuGitHub User negezorGitHub User TimJohnsGitHub User thomasbntGitHub User atinuxGitHub User stvnwGitHub User spnc-omzGitHub User gangsthubGitHub User amplitudesxdGitHub User nWackyGitHub User reslearGitHub User samenickGitHub User t0yoheiGitHub User wckgoGitHub User YunYouJunGitHub User censujiangGitHub User nozomuikutaGitHub User mukundshahGitHub User HigherOrderLogicGitHub User imgtaGitHub User felixranesberger
1.6K
Commits
473
Issues Closed
28
Contributors
105K downloads
per day, on average

Unhead is used and trusted by thousands of developers and companies around the world.

3.6M
Downloads
/ month
688
Total Stars

Funded by the community

Unhead is completely free and open-source due to the generous support of the community.