<Head />

The Head component lets you render elements into the document <head> on web, and integrates with native platform features like Apple Handoff and Spotlight Search on iOS.

Usage

app/blog/[slug].tsx

import { Head, useLoader } from 'one'
export async function loader({ params }) {
const post = await getPost(params.slug)
return { post }
}
export default function BlogPost() {
const { post } = useLoader()
return (
<>
<Head>
<title>{post.title}</title>
<meta name="description" content={post.excerpt} />
<meta property="og:title" content={post.title} />
<meta property="og:description" content={post.excerpt} />
<meta property="og:image" content={post.image} />
</Head>
<article>
<h1>{post.title}</h1>
{/* ... */}
</article>
</>
)
}

Props

PropTypeDescription
childrenReactNodeStandard HTML head elements like <title>, <meta>, <link>, etc.

Supported Elements

The Head component accepts standard HTML head elements:

  • <title> - Page title
  • <meta> - Meta tags (description, Open Graph, Twitter Cards, etc.)
  • <link> - Stylesheets, favicons, preload hints
  • <script> - External scripts
  • <style> - Inline styles
<Head>
{/* Page title */}
<title>My Page Title</title>
{/* Meta tags */}
<meta name="description" content="Page description" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
{/* Open Graph */}
<meta property="og:title" content="My Page" />
<meta property="og:description" content="Page description" />
<meta property="og:image" content="https://example.com/image.png" />
<meta property="og:url" content="https://example.com/page" />
{/* Twitter Cards */}
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="My Page" />
{/* Favicon */}
<link rel="icon" href="/favicon.ico" />
{/* Preload fonts */}
<link rel="preload" href="/fonts/custom.woff2" as="font" type="font/woff2" crossOrigin="" />
</Head>

Dynamic Metadata

Use loader data or component state to set dynamic metadata:

app/products/[id].tsx

import { Head, useLoader, useParams } from 'one'
export async function loader({ params }) {
const product = await getProduct(params.id)
return { product }
}
export default function ProductPage() {
const { product } = useLoader()
const ogImageUrl = `/api/og?title=${encodeURIComponent(product.name)}&price=${product.price}`
return (
<>
<Head>
<title>{product.name} | My Store</title>
<meta name="description" content={product.description} />
<meta property="og:title" content={product.name} />
<meta property="og:image" content={ogImageUrl} />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="product:price:amount" content={String(product.price)} />
<meta property="product:price:currency" content="USD" />
</Head>
{/* Page content */}
</>
)
}

Platform Behavior

Web

On web, Head renders its children directly into the document’s <head> element. Multiple Head components can be used across your app - they will all contribute to the final head content.

iOS (Native)

On iOS, Head integrates with native platform features:

  • Apple Handoff: Continue browsing on other Apple devices
  • Spotlight Search: Make your content searchable in iOS Spotlight

Enable these features using special meta properties:

<Head>
<title>My Article</title>
<meta property="og:title" content="My Article" />
<meta property="og:description" content="Article description" />
<meta property="og:url" content="https://example.com/article" />
{/* Enable Apple Handoff */}
<meta property="expo:handoff" content="true" />
{/* Enable Spotlight Search indexing */}
<meta property="expo:spotlight" content="true" />
</Head>
Meta PropertyDescription
expo:handoffSet to "true" to enable Apple Handoff for this page
expo:spotlightSet to "true" to index this page in iOS Spotlight Search

Android

On Android, Head currently has no effect. Native metadata features may be added in future versions.

Creating a Reusable Head Component

For consistent metadata across your app, create a wrapper component:

features/HeadInfo.tsx

import { Head } from 'one'
type HeadInfoProps = {
title: string
description?: string
image?: string
url?: string
}
export function HeadInfo({ title, description, image, url }: HeadInfoProps) {
const fullTitle = `${title} | My App`
return (
<Head>
<title>{fullTitle}</title>
{description && <meta name="description" content={description} />}
{/* Open Graph */}
<meta property="og:title" content={fullTitle} />
{description && <meta property="og:description" content={description} />}
{image && <meta property="og:image" content={image} />}
{url && <meta property="og:url" content={url} />}
{/* Twitter */}
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content={fullTitle} />
{description && <meta name="twitter:description" content={description} />}
{image && <meta name="twitter:image" content={image} />}
</Head>
)
}

Use it in your pages:

import { HeadInfo } from '~/features/HeadInfo'
export default function AboutPage() {
return (
<>
<HeadInfo title="About Us" description="Learn about our company" image="/images/about-og.png" />
{/* Page content */}
</>
)
}

Edit this page on GitHub.