<Head> Component
Import <Head> from @unhead/react, then place native lowercase <title>, <meta>, <link>, <style>, and <script> elements inside it.
<Head> provides HTML-like JSX syntax. Use useHead() instead when you need typed object input or Unhead-specific entry options.
Basic Usage
import { Head } from '@unhead/react'
function App() {
return (
<Head>
<title>My Site</title>
<meta name="description" content="Site description" />
</Head>
)
}
Supported Tags
Metadata
<Head>
<title>Page Title</title>
<meta name="description" content="A concise, page-specific summary of this page" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="robots" content="index,follow" />
<meta charSet="utf-8" />
</Head>
Google does not set a fixed meta-description length; search snippets are truncated to fit the device. Write a useful page-specific summary instead of targeting a character count. See Google's snippet guidance.
Links
<Head>
{/* Stylesheets */}
<link rel="stylesheet" href="/styles.css" />
{/* Preloading Critical Resources */}
<link rel="preload" href="/critical-font.woff2" as="font" type="font/woff2" crossOrigin="anonymous" />
{/* Performance Hints */}
<link rel="dns-prefetch" href="//api.example.com" />
<link rel="preconnect" href="https://api.example.com" />
{/* Icons */}
<link rel="icon" href="/favicon.ico" sizes="32x32" />
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
</Head>
Scripts
<Head>
{/* Async Loading */}
<script async src="https://example.com/analytics.js" />
{/* Module/NoModule Pattern */}
<script type="module" src="/modern.js" />
<script noModule src="/legacy.js" />
{/* Inline Scripts */}
<script type="application/ld+json">
{JSON.stringify({
'@context': 'https://schema.org',
'@type': 'WebSite',
'name': 'Your Site Name'
})}
</script>
</Head>
Raw HTML
<Head> supports React's dangerouslySetInnerHTML prop on <title>, <script>, <style>, and <noscript>. It cannot be combined with children.
Use a string child for ordinary inline scripts and styles. Use dangerouslySetInnerHTML when the content must be parsed as raw markup, such as an HTML fallback inside <noscript>:
const trustedFallback = {
__html: '<img src="/pixel.gif" alt="">'
}
<Head>
<noscript dangerouslySetInnerHTML={trustedFallback} />
</Head>
Only pass trusted or sanitized content. Untrusted HTML can introduce an XSS vulnerability. See React's dangerouslySetInnerHTML guidance.
Open Graph
<Head>
<meta property="og:title" content="Page Title" />
<meta property="og:description" content="Page description" />
<meta property="og:image" content="https://example.com/image.jpg" />
<meta property="og:url" content="https://example.com/page" />
<meta property="og:type" content="website" />
</Head>
Twitter Cards
<Head>
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site" content="@username" />
<meta name="twitter:title" content="Page Title" />
<meta name="twitter:description" content="Page description" />
<meta name="twitter:image" content="https://example.com/image.jpg" />
</Head>
Unhead-Specific Options
Tag Priority
For Unhead-specific options such as tagPriority, use useHead() so TypeScript can validate the tag configuration:
useHead({
title: 'Must Load First',
link: [
{ rel: 'stylesheet', href: '/styles.css', tagPriority: 'high' }
],
script: [
{ src: '/analytics.js', tagPriority: 'low' }
]
})
Document Position
Use tagPosition for tags outside the document head:
useHead({
script: [
{ src: '/early.js', tagPosition: 'head' },
{ src: '/late.js', tagPosition: 'bodyClose' }
]
})
Deduplication
Unhead automatically dedupes tags based on their content and attributes. Later instances override earlier ones:
<>
<Head>
<meta name="description" content="Will be overridden" />
</Head>
<Head>
<meta name="description" content="Final description" />
</Head>
</>