Head Component

The <Head> component manages <head> tags from JSX. It renders nothing in the body; on the client it updates document.head directly. For programmatic HTML strings (Open Graph, JSON-LD helpers), see SEO & Meta. For route-level titles in the default SSR build, use export const metadata — SSR & SSG.

Basic Usage

import { Head } from '@emberkit/core';

function MyPage() {
  return (
    <>
      <Head>
        <title>My Page - EmberKit</title>
        <meta name="description" content="A page built with EmberKit" />
      </Head>
      <h1>Hello World</h1>
    </>
  );
}

During SSR, this produces:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>My Page - EmberKit</title>
  <meta name="description" content="A page built with EmberKit">
</head>
<body>
  <h1>Hello World</h1>
</body>
</html>

Shorthand Props

For common tags, use props instead of raw JSX:

<Head
  title="My Page"
  description="Page description"
  keywords={['emberkit', 'framework', 'typescript']}
  author="EmberKit Team"
  robots="index, follow"
  canonical="https://example.com/my-page"
/>

Supported Props

Shorthand Props Reference

PropTypeHTML Output
titlestring<title> + <meta name="title">
descriptionstring<meta name="description">
keywordsstring[]<meta name="keywords"> (comma-separated)
authorstring<meta name="author">
robotsstring<meta name="robots">
canonicalstring<link rel="canonical">

Open Graph

<Head
  og={{
    type: 'article',
    title: 'My Page',
    description: 'Page description for social sharing',
    url: 'https://example.com/my-page',
    image: 'https://example.com/og-image.png',
    locale: 'en_US',
    siteName: 'My Site',
  }}
/>

Twitter Cards

<Head
  twitter={{
    card: 'summary_large_image',
    site: '@emberkit',
    creator: '@author',
    title: 'My Page',
    description: 'Page description',
    image: 'https://example.com/twitter-image.png',
  }}
/>

Combining Children and Props

You can mix shorthand props with raw JSX children:

<Head title="My Page" description="Description">
  <meta property="og:image" content="https://example.com/og.png" />
  <link rel="icon" href="/favicon.ico" />
</Head>

When children are provided, they take precedence — the shorthand props are ignored.

Multiple <Head> Components

Use multiple <Head> components across your component tree. All tags are collected and merged into <head>:

// Layout provides default meta
function Layout({ children }) {
  return (
    <>
      <Head>
        <meta name="theme-color" content="#0b0f19" />
        <meta property="og:site_name" content="My Site" />
      </Head>
      {children}
    </>
  );
}

// Page provides page-specific meta
function AboutPage() {
  return (
    <>
      <Head>
        <title>About Us - My Site</title>
        <meta name="description" content="Learn about our team" />
      </Head>
      <h1>About Us</h1>
    </>
  );
}

Structured Data (JSON-LD)

Use children for structured data scripts:

import { Head, generateArticleSchema } from '@emberkit/core';

function ArticlePage() {
  const schema = generateArticleSchema({
    title: 'My Article',
    description: 'Article description',
    author: 'John Doe',
    publishedAt: '2025-01-15',
    url: 'https://example.com/article',
  });

  return (
    <>
      <Head>
        <title>My Article</title>
        <script type="application/ld+json">{schema}</script>
      </Head>
      <article>
        <h1>My Article</h1>
      </article>
    </>
  );
}

How It Works

SSR

During server-side rendering, <Head>:

  1. Renders its children to an HTML string
  2. Registers the HTML to an internal head content registry
  3. Returns null (nothing in the page body)

During SSR, registered tags are available via drainHeadContent() from @emberkit/core. The built-in CLI server entry injects route metadata exports; use a custom src/entry-server.tsx if you need to merge drainHeadContent() into your HTML template.

Client-Side Navigation

During SPA navigation, <Head>:

  1. Renders its children to an HTML string
  2. Parses the HTML and updates document.head directly
  3. Tags are marked with data-ek-head so re-renders replace (not duplicate) managed tags

API Reference

interface HeadProps {
  children?: JSXNode | JSXNode[];
  title?: string;
  description?: string;
  og?: {
    title?: string;
    description?: string;
    type?: string;
    url?: string;
    image?: string;
    locale?: string;
    siteName?: string;
  };
  twitter?: {
    card?: string;
    site?: string;
    creator?: string;
    title?: string;
    description?: string;
    image?: string;
  };
  canonical?: string;
  robots?: string;
  keywords?: string[];
  author?: string;
}

Next Steps

  • SEO & Meta - Programmatic meta generation with generateMeta()
  • SSR - Server-side rendering pipeline
  • Components - Component patterns