@useblok/render
v0.1.1
Published
SSR-friendly renderer for Blok JSON pages. Docs: https://docs.useblok.dev
Downloads
87
Maintainers
Readme
@useblok/render
Headless, SSR-friendly renderer for Blok JSON. Ship published pages without pulling in the editor, drag-and-drop, or the Zustand store.
Why
@useblok/core is the editor. For production pages — Next.js App Router, React Server Components, static export — you only need the render path. @useblok/render is ~1 KB gzipped and has no runtime dependency on the editor.
Install
npm install @useblok/render @useblok/coreQuickstart
import { BlokRender } from "@useblok/render";
import { config } from "./blok.config";
import type { Data } from "@useblok/core";
export default async function Page() {
const data: Data = await loadFromCMS();
return <BlokRender config={config} data={data} />;
}Works inside React Server Components. No "use client" required unless a block's render needs it.
API
<BlokRender config data />
Top-level renderer. Applies config.root.render (if any) and renders data.content.
| Prop | Type | Notes |
| --------------- | ---------------------------------------------- | --------------------------------------------------------------------- |
| config | Config | Same config you pass to <Blok />. |
| data | Data | { root, content, zones } — the Blok document JSON. |
| fallback | (type, block) => ReactNode | Optional. Rendered when a block type isn't registered in config. |
| errorBoundary | boolean | Default true. Wraps each block; on throw, renders null. |
| onError | (error, block) => void | Called when a wrapped block throws. Pair with your error logger. |
<BlokZone config data zoneId />
Render a single zone — useful inside custom root components or for rendering just a specific slot.
<BlokZone config={config} data={data} zoneId={slotZoneId(blockId, "children")} />BlokRenderContext
The blok prop every block renderer receives:
interface BlokRenderContext {
id: string;
renderSlot: (fieldName: string) => ReactNode;
}slotZoneId(blockId, fieldName) · ROOT_ZONE
Helpers matching @useblok/core's zone naming. Use when you need to look into data.zones directly.
SSR notes
- The renderer itself is synchronous and has no
useEffect/useState— it streams cleanly. - Error boundaries use
getDerivedStateFromError, which runs in SSR. A thrown block renders asnullinstead of breaking the stream (whenerrorBoundary: true, the default). - Block
renderfunctions are your code. If a block uses browser-only APIs, gate it inside that block, not here.
