Content pages
Terms, privacy, about us and other merchant pages as ready, sanitised HTML with downloadable attachments
Content pages are the texts a merchant (or an AI agent) writes in Behio: terms and conditions, privacy policy, returns, about us, contact. Each page has a slug, a title, SEO fields, the body and optional downloadable attachments (price lists, forms, PDFs). They work with both e-shop keys and website keys.
List pages
const { data } = await client.pages.list('cs');
// data.pages: [{ slug, title, isActive, updatedAt }]Use the list for the footer navigation and the sitemap (updatedAt is epoch ms for lastmod). Only published pages are returned.
One page
import { RichText } from '@behio/storefront-sdk/react';
const { data: page, error } = await client.pages.get('obchodni-podminky', 'cs');
if (error?.status === 404 || !page) {
// unknown or unpublished page: render your 404
}
<h1>{page.title}</h1>
<RichText html={page.contentHtml} as="article" />contentHtml (SDK 2.20.0) is always a string with ready, sanitised HTML, empty when the page has no body. You never have to know how the page was stored:
- pages written in the admin editor or by an AI agent are HTML,
- older pages written in markdown are converted on the server,
- headings start at
<h2>, because your page renders the single<h1>fromtitle(a leading markdown heading that repeats the title is dropped), - scripts, event handlers,
javascript:links and unsafe inline styles are removed before the response leaves the API.
Render it as is. RichText wraps it in an element with the class behio-rich-text, so style headings, lists, tables, images and the story blocks (.bh-figure, .bh-callout, .bh-button and the other bh-* classes) under that one class.
content is deprecated. It is the body as a string: sanitised HTML, or markdown for older pages written in markdown. It stays for storefronts built before 2.20.0. New code reads contentHtml, which is always ready HTML.
In a Next.js server component you can skip the client component and render the string directly; the HTML is already sanitised by the API:
<article className="behio-rich-text" dangerouslySetInnerHTML={{ __html: page.contentHtml }} />Attachments
{page.attachments.length > 0 && (
<ul>
{page.attachments.map((file) => (
<li key={file.url}>
<a href={file.url} download>
{file.name}
</a>
{file.description && <p>{file.description}</p>}
<small>{Math.ceil(file.fileSize / 1024)} kB</small>
</li>
))}
</ul>
)}Each attachment is { name, description, url, mimeType, fileSize }. The field is url (not fileUrl); Behio hosts the file.
SEO
seoTitle and seoDescription fall back to title when empty; ogTitle, ogDescription and ogImage are for social previews.
React hooks
import { usePages, usePage, RichText } from '@behio/storefront-sdk/react';
const { data: pages } = usePages('cs');
const { data: page, isLoading } = usePage(slug, 'cs');
if (page) return <RichText html={page.contentHtml} as="article" />;RichText
import { RichText } from '@behio/storefront-sdk/react';
<RichText html={product.longDescription} />
<RichText html={post.content.html} as="article" className="prose" />| Prop | Type | Default | |
|---|---|---|---|
html | string | null | undefined | Renders nothing when empty | |
className | string | Added next to behio-rich-text | |
as | "div" | "article" | "section" | "div" | Wrapper element |
Use it only for fields the Behio API sanitises: page.contentHtml, a blog post's content.html and product shortDescription / longDescription. Never pass HTML from a visitor, a query string or another service.