Announcing Unhead v2

The full stack <head> package for any framework.

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

Hello useHead()

Unhead aims to provide bullet-proof primitives for a minimal yet powerful API surface.

✅ 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,
    },
  },
})

Built For Reactive Lifecycles

All side effects are tracked so that unmounting a component will revert its head modifications and reactive updates can be made at any time.
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',
  }],
})
<!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 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

// Unhead tags are built to tree-shake, it just works
if (import.meta.server) {
  useHead({
    meta: [{
      name: 'description',
      content: 'Hello World',
    }],
    script: [{
      innerHTML: 'console.log("Hello World")',
    }],
  })
}

Unhead Principals

Full Featured Developer Experience
Full featured modules that do everything you expect and more.
Optimized for Performance
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 LittleSoundGitHub User vetruvetGitHub User s-en-oGitHub User 719mediaGitHub User abbassiddiqiGitHub User Roman3349GitHub User spnc-omzGitHub User stvnwGitHub User atinuxGitHub User thomasbntGitHub User TimJohnsGitHub User negezorGitHub User mittalyashuGitHub User amplitudesxdGitHub User nWackyGitHub User reslearGitHub User samenickGitHub User t0yoheiGitHub User wckgoGitHub User YunYouJunGitHub User censujiangGitHub User Mini-ghostGitHub User TheAlexLichterGitHub User antfuGitHub User arashsheyda
1.8K
Commits
500
Issues Closed
28
Contributors
114K downloads
per day, on average

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

4M
Downloads
/ month
769
Total Stars

Funded by the community

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