React¶
@easeo/react provides <EaseoHead />, which keeps document.head in sync on
the client.
Simple: a component¶
import { EaseoHead } from "@easeo/react";
export function About() {
return (
<>
<EaseoHead
entity={{ entityType: "page", title: "About", description: "About us." }}
route="/about"
config={{ canonicalHost: "example.com", publicBaseUrl: "https://example.com" }}
/>
<h1>About</h1>
</>
);
}
Complex: a router-driven app¶
<EaseoHead /> updates whenever its props change, so mount it once near the
router outlet and pass the current route.
import { BrowserRouter, Routes, Route, useLocation } from "react-router-dom";
import { EaseoHead } from "@easeo/react";
import { config } from "./seo";
function ProductPage({ product }: { product: Product }) {
const route = `/products/${product.slug}`;
return (
<>
<EaseoHead
entity={{
entityType: "product",
title: product.name,
description: product.shortDescription,
image: product.imageUrl,
sku: product.sku,
price: product.price,
priceCurrency: product.currency,
availability: product.inStock ? "InStock" : "OutOfStock",
}}
route={route}
config={config}
/>
<ProductDetail product={product} />
</>
);
}
// src/seo.ts
import type { SEOConfig } from "@easeo/core";
export const config: SEOConfig = {
canonicalHost: "shop.example.com",
publicBaseUrl: "https://shop.example.com",
siteName: "Example Shop",
titleTemplate: "{title} - Example Shop",
defaultOgImage: "https://shop.example.com/assets/og-image.png",
};
Complex: server rendering and static generation¶
<EaseoHead /> is SSR-safe: it renders nothing when document is absent. For
SSR or SSG, build the payload and inject the head into your HTML template:
import { buildSeoPayload } from "@easeo/core";
import { config } from "./seo";
import { renderToString } from "react-dom/server";
export function renderPage(product: Product) {
const payload = buildSeoPayload(
{ entityType: "product", title: product.name, description: product.shortDescription },
`/products/${product.slug}`,
config
);
const body = renderToString(<ProductDetail product={product} />);
return `<!doctype html>
<html>
<head>${payload.renderHtml()}</head>
<body>${body}</body>
</html>`;
}
Notes¶
- The component renders
null; it is not a visual element. renderHtml()output is already escaped, so it is safe to inject.- Mount one
<EaseoHead />per route so the head always matches the page.