Stone.jsDocs
Paradigm

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.

app/pages/TaskPage.tsxts
head ({ data }: { data: Task }): HeadContext {
  return {
    title: data.title,
    titleTemplate: '%s · Tasks',
    description: `Task: ${data.title}`,
    metas: [{ property: 'og:type', content: 'article' }]
  }
}

#The HeadContext

OptionTypeDescription
titlestringThe document title.
titleTemplatestringA wrapper for the title, e.g. '%s · Tasks'.
descriptionstringThe meta description.
metasMetaDescriptor[]Arbitrary meta tags (Open Graph, Twitter, ...).
linksLinkDescriptor[]Link tags (canonical, preconnect, ...).
scriptsScriptDescriptor[]Scripts (src or inline content).
jsonLdobject[]JSON-LD structured data blocks.
htmlAttributes / bodyAttributesRecord<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.

app/pages/TaskPage.tsxts
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.

app/pages/TaskPage.tsxts
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.

app/pages/DraftPage.tsxts
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.

app/pages/Gallery.tsxtsx
import { useHead } from '@stone-js/use-react'

export function Gallery () {
  useHead({ links: [{ rel: 'preconnect', href: 'https://images.example.com' }] })
  return <div className='gallery'>{/* ... */}</div>
}

Stone.js

Your app exists in every runtime. Until you run it.

An open-source project by Stone Foundation
Created by Mr. Stone (Evens Pierre)