Block Schema & Field Types
All field types, the defineBlock + fields builder, field options, repeaters, and select options.
All Field Types
Define a block's editable props with the fields.*() builder inside defineBlock. Each builder returns a field definition; the key you give it in props becomes the content key.
| Builder | Description | Value Type |
|---|---|---|
fields.text() | Single-line text input | string |
fields.textarea() | Multi-line text area | string |
fields.richText() | WYSIWYG editor (Tiptap) | string (HTML) |
fields.markdown() | Markdown editor | string (Markdown) |
fields.number() | Number input | number |
fields.date() | Date picker | string (ISO date) |
fields.datetime() | Date & time picker | string (ISO) |
fields.boolean() | Toggle switch | boolean |
fields.color() | Color picker | string (hex) |
fields.media() | Image/video upload | string or string[] |
fields.link() | Internal/external link | string |
fields.url() | URL input | string |
fields.email() | Email input | string |
fields.select() | Dropdown (single choice) | string |
fields.radio() | Radio group (single choice) | string |
fields.multiselect() | Multiple choice | string[] |
fields.relation() | Reference records from a model | record or record[] |
fields.repeater() | Array of nested field groups | object[] |
fields.table() | Editable table grid | { columns, rows } |
fields.json() | Raw JSON editor | JSON value |
fields.form() | Pick a Cmssy form | string (form id) |
fields.pageSelector() | Pick page(s) | PageRef[] |
Most builders take only the base options below. fields.select(), fields.radio() and fields.multiselect() require an options array; fields.media() accepts multiple; fields.relation() needs a model (the referenced model's slug) and optionally mode: "all", multiple, sort and limit. A relation stores record id(s); the delivery API resolves them to full records before your component renders.
Defining a Block
A block is declared with defineBlock. Its editable fields live under props:
import { defineBlock, fields } from "@cmssy/react";
import Hero from "./Hero";
export const heroProps = {
heading: fields.text({ label: "Heading", required: true, defaultValue: "Welcome" }),
description: fields.textarea({ label: "Description" }),
};
export const heroBlock = defineBlock({
type: "hero",
label: "Hero",
component: Hero,
props: heroProps,
});
Export the props object on its own and type the component from it - BlockProps<typeof heroProps> - so the schema stays the only place a field is named, and the value types in the table above become the types your component sees. See Block development.
Field Options
Every fields.*() builder accepts the same base options:
fields.text({
label: "Heading",
required: true,
defaultValue: "Welcome",
placeholder: "Enter text",
helperText: "Main heading",
})
Available keys: label, required, defaultValue, placeholder, helperText. Select and repeater fields add a few more (below).
Select & Multiselect
Options are a plain array of strings:
props: {
layout: fields.select({
label: "Layout",
options: ["grid", "list", "carousel"],
defaultValue: "grid",
}),
tags: fields.multiselect({
label: "Tags",
options: ["featured", "new"],
}),
}
Repeater (Arrays)
Use itemSchema — a map of nested fields.*() — to describe each row:
props: {
features: fields.repeater({
label: "Features",
maxItems: 6,
itemSchema: {
icon: fields.text({ label: "Icon Name", defaultValue: "Star" }),
title: fields.text({ label: "Title", required: true }),
description: fields.textarea({ label: "Description" }),
},
}),
}
In your component:
export default function Features({ content }) {
return (
<div className="grid grid-cols-3 gap-6">
{(content.features ?? []).map((f, i) => (
<div key={i}><h3>{f.title}</h3><p>{f.description}</p></div>
))}
</div>
);
}
Repeater also supports itemLabel, addButtonLabel, minItems, maxItems, and collapsible.