Frontend
Head & metadata
Good metadata is not an afterthought: it is what search engines and social cards read. A page declares its head in one place, and on SSR/SSG it is rendered straight into the HTML, so crawlers see it without running your JavaScript.
#Per-page head
Return a HeadContext from a page's head(). It can depend on the page's data, so titles and descriptions reflect what is actually on the page.
head ({ data }: { data: Task }): HeadContext {
return {
title: data.title,
titleTemplate: '%s · Tasks',
description: `Task: ${data.title}`,
metas: [{ property: 'og:type', content: 'article' }]
}
}#The HeadContext
| Option | Type | Description |
|---|---|---|
| title | string | The document title. |
| titleTemplate | string | A wrapper for the title, e.g. '%s · Tasks'. |
| description | string | The meta description. |
| metas | MetaDescriptor[] | Arbitrary meta tags (Open Graph, Twitter, ...). |
| links | LinkDescriptor[] | Link tags (canonical, preconnect, ...). |
| scripts | ScriptDescriptor[] | Scripts (src or inline content). |
| jsonLd | object[] | JSON-LD structured data blocks. |
| htmlAttributes / bodyAttributes | Record<string,string> | Attributes on <html> / <body> (e.g. lang). |
#Social cards & canonical
Open Graph and Twitter cards are meta tags; a canonical URL is a link. Set them on the page that owns the content, driven by its data, and every share renders a proper card.
head ({ data }: { data: Task }): HeadContext {
const url = `https://tasks.example.com/tasks/${data.id}`
return {
title: data.title,
description: data.summary,
links: [{ rel: 'canonical', href: url }],
metas: [
// Open Graph
{ property: 'og:type', content: 'article' },
{ property: 'og:title', content: data.title },
{ property: 'og:description', content: data.summary },
{ property: 'og:url', content: url },
{ property: 'og:image', content: data.cover },
// Twitter
{ name: 'twitter:card', content: 'summary_large_image' },
{ name: 'twitter:title', content: data.title }
]
}
}#Structured data (JSON-LD)
Rich results come from JSON-LD. The jsonLd field renders each object as a <script type="application/ld+json">, so search engines read your entities directly, again baked into the HTML on SSR and SSG.
head ({ data }): HeadContext {
return {
title: data.title,
jsonLd: [{
'@context': 'https://schema.org',
'@type': 'CreativeWork',
name: data.title,
dateModified: data.updatedAt
}]
}
}#Robots & crawling
Steer crawlers per page with a robots meta, keep a draft out of the index without touching routing.
head () {
return { metas: [{ name: 'robots', content: 'noindex, nofollow' }] }
}#From a component
Deep in the tree, a component can contribute to the head with useHead, merging onto what the page declared. Useful for widgets that need their own preconnect or meta.
import { useHead } from '@stone-js/use-react'
export function Gallery () {
useHead({ links: [{ rel: 'preconnect', href: 'https://images.example.com' }] })
return <div className='gallery'>{/* ... */}</div>
}