Getting Started
1. Define a block
A block needs a label, a Zod schema, and a component to render it.
import { RenderBlocks, RichTextEditor } from '@repo/cms'
import { zaf } from '@repo/form'
import { z } from 'zod'
import ContentBlock from './ContentBlock.svelte'
const blocks = {
content: {
label: 'Content',
schema: z.object({
content: zaf(RichTextEditor.schema, { component: RichTextEditor.Root }),
}),
component: RenderBlocks.renderComponent(ContentBlock, {}),
},
}
2. Edit blocks in a form
Use BlockField.Root inside a form schema with zaf:
import { BlockField } from '@repo/cms'
import { FormField, zaf } from '@repo/form'
import { z } from 'zod'
const pageSchema = z.object({
title: z.string(),
blocks: zaf(z.array(z.any()), {
component: FormField.renderComponent(BlockField.Root, { blocks }),
}),
})
Then render with TypedForm:
<script lang="ts">
import { TypedForm } from '@repo/form'
</script>
<TypedForm.Remote form={createPageForm} schema={pageSchema} />
3. Render blocks on the frontend
<script lang="ts">
import { RenderBlocks } from '@repo/cms'
type Props = { blocks: Record<string, Block>; value: BlockValue[] }
const { blocks, value }: Props = $props()
</script>
<RenderBlocks.Root {blocks} {value} />
Each block's component receives its values as a data prop.