Spillway CMSStructured content like Drupal. Page building like Puck. Setup like Ghost. AI that drafts, people who approve.
Menu

Blocks reference

<!-- Generated by pnpm docs:build (docs-reference) from packages/blocks/src/config.tsx and meta.ts. Do not edit by hand; edit the source and run the command. -->

Every block of @spillway-cms/blocks with its editor fields, options and default props. Blocks are Puck components: the admin shows the fields in the right-hand panel and the server renders the props with @puckeditor/core/rsc. Props marked resolved are attached by the server at render time and never stored. The narrative guide is blocks.md.

Summary

BlockCategoryDescription
ColumnsLayoutTwo to four side-by-side columns, each a slot that holds other blocks. Stacks on small screens.
SpacerLayoutVertical space (s, m, l, xl).
DividerLayoutA horizontal rule.
HeadingContentA standalone heading (h1 to h4) with alignment.
TextContentBody copy. Plain text split into paragraphs on blank lines, or raw HTML.
ImageContentA single image with required alt text, optional caption and width (normal, wide, full).
EmbedContentRaw embed HTML (for example a YouTube iframe) in a responsive 16:9 frame.
ButtonContentA single button with alignment; its emphasis (primary, secondary or a text link) comes from its style.
HeroMarketingLarge opening section with an eyebrow, title, subtitle, up to two buttons and an optional background image.
CallToActionMarketingA title, short text and one button; its style (a colored band, a bordered card or one the site defines) comes from Brand → Styles.
CardsMarketingA grid of cards with title, text, optional link and image, in 2 to 4 columns.
CollectionMarketingA saved query (collection) of entities rendered as cards, a list or a grid, optionally with visitor filters (keyword, taxonomy, select, date range) and a pager; items are filled in by the server at render time.
CalendarMarketingA month grid or date list of the event occurrences in a collection, with a link to its iCal feed; filled in by the server at render time.
FormMarketingA lead-capture form defined under Forms in the admin, referenced by key. Fields, labels and the success message come from the definition.
SharedMarketingA block saved in the component library (Shared blocks in the admin), referenced by key and rendered by the server; edit it once, update everywhere.
PersonalizeMarketingTwo slots, Default and Variant; visitors who match an audience (Audiences in the admin) see the variant. The server decides per visitor after the page loads, so pages stay cached.
ExperimentMarketingAn A/B test: slots a (control), b and optional c; visitors of a running experiment (Experiments in the admin) are assigned a variant by weight and the results screen reports conversions per variant.
RegistryBrowseMarketingSearch and browse the package registry (modules, themes, kits): a GET search form, kind tabs, a sort, result cards with badges and a pager; filled in by the registry service from the page URL. Placeholder on instances that do not host the registry.
RegistryPackageMarketingThe detail page of one registry package, resolved from the last segment of the page path (/registry/<name>): header with badges, install command with a copy button, publisher and links, capability sheet, compatibility, versions, advisories, deprecation notice, README, changelog and a "For agents" section linking manifest.json.
RegistryStatsMarketingThe registry totals: packages by kind, publishers and downloads, as a row of figures.
ThemeGalleryMarketingThe theme directory: registry kits of kind "theme" as cards with a screenshot, description, publisher and Preview and Details links.
PublisherProfileMarketingA publisher’s public profile (handle, name, verified badge, bio, website, maintainers) and their packages; the handle comes from the page path (/registry/publishers/<handle>) or the handle prop.
OrgProfileMarketingAn organization’s public profile (handle, name, verified badge, website, members with their roles, the namespaces it owns) and the packages published under those namespaces; the handle comes from the page path (/registry/orgs/<handle>) or the handle prop.
DocsFeedbackMarketing"Was this page helpful?" with Yes and No buttons and an optional comment, posted to a form (docs_feedback by default) with the page path and the documented version as hidden fields; works without JavaScript and asks for no personal data.
StatusBoardMarketingA list of Spillway instances with their state (up, degraded or down), version, when each was last checked and a 90-day uptime bar; the server fetches every instance’s /status.json (3 s timeout, cached for a minute) and reads the history the probe step records every five minutes.
ModuleBlockModulesA block an installed module provides (module name, block key and the block’s own props); rendered by the module on the server, with a placeholder when the module is disabled or missing.

Layout

Columns

Two to four side-by-side columns, each a slot that holds other blocks. Stacks on small screens.

AI hint: Use to place blocks side by side, for example an Image next to a Text. Each entry in "columns" has a "content" array of child blocks. Keep to 2 or 3 columns for readability.

PropLabelTypeOptionsDefault
columnsColumnsarray[{"content":[]},{"content":[]}]
columns[].contentContentslotchild blocks
gapGapselect"normal""normal"

Spacer

Vertical space (s, m, l, xl).

AI hint: Use sparingly to add breathing room between sections. Blocks already have padding.

PropLabelTypeOptionsDefault
sizeSizeradio"s", "m", "l", "xl""m"

Divider

A horizontal rule.

AI hint: Use to separate unrelated sections. Do not place directly after a Spacer.

PropLabelTypeOptionsDefault
widthWidthradio"normal", "narrow""normal"

Content

Heading

A standalone heading (h1 to h4) with alignment.

AI hint: Use to start a section. Prefer h2 for sections and h3 for sub-sections; the Hero already provides the h1. Keep headings short and specific.

PropLabelTypeOptionsDefault
textTexttext"Section heading"
levelLevelselect"h1", "h2", "h3", "h4""h2"
alignAlignmentradio"left", "center", "right""left"

Text

Body copy. Plain text split into paragraphs on blank lines, or raw HTML.

AI hint: Use for prose. Prefer format "paragraphs" and separate paragraphs with a blank line. Use "lead" size for a single intro paragraph. Only use "html" when markup such as lists or links is required.

PropLabelTypeOptionsDefault
contentContenttextarea"Write a paragraph here. Leave a blank line between paragraphs.\n\nThis is a sec
formatFormatselect"paragraphs", "html""paragraphs"
sizeSizeradio"normal", "lead""normal"
alignAlignmentradio"left", "center", "right""left"

Image

A single image with required alt text, optional caption and width (normal, wide, full).

AI hint: Use only with a real image URL from the media library (/media/...). Always write descriptive alt text; use an empty alt only for purely decorative images.

PropLabelTypeOptionsDefault
srcImage URLtextplaceholder: /media/<id>/<filename>""
altAlt text (required)textplaceholder: Describe the image""
captionCaptiontext""
widthWidthradio"normal", "wide", "full""normal"
roundedRounded cornersradiotrue, falsetrue

Embed

Raw embed HTML (for example a YouTube iframe) in a responsive 16:9 frame.

AI hint: Use only when the user provides embed code or a known embeddable URL. Put the full iframe markup in "html". Never invent video IDs.

PropLabelTypeOptionsDefault
htmlEmbed HTMLtextareaplaceholder: <iframe src="https://www.youtube.com/embed/..."></iframe>""
captionCaptiontext""

Button

A single button with alignment; its emphasis (primary, secondary or a text link) comes from its style.

AI hint: Use for a standalone link styled as a button. Label is a verb phrase; href is a site path or full URL.

PropLabelTypeOptionsDefault
labelLabeltext"Learn more"
hrefLinktext"#"
alignAlignmentradio"left", "center", "right""left"

Marketing

Hero

Large opening section with an eyebrow, title, subtitle, up to two buttons and an optional background image.

AI hint: Use once, at the top of a landing page. Title under 10 words, subtitle one or two sentences. Primary button is the main action; secondary is optional. Leave backgroundImage empty unless a real image URL is known.

PropLabelTypeOptionsDefault
eyebrowEyebrowtextplaceholder: Short label above the title"Introducing"
titleTitletext"A headline that says what you do"
subtitleSubtitletextarea"One or two sentences that explain the value and who it is for."
primaryLabelPrimary button labeltext"Get started"
primaryHrefPrimary button linktextplaceholder: /get-started"#"
secondaryLabelSecondary button labeltext"Learn more"
secondaryHrefSecondary button linktext"#"
backgroundImageBackground image URLtextplaceholder: /media/...""
alignAlignmentradio"left", "center""center"
sizeSizeradio"default", "large""default"

CallToAction

Label in the editor: Call to action.

A title, short text and one button; its style (a colored band, a bordered card or one the site defines) comes from Brand → Styles.

AI hint: Use near the end of a page to ask for one action. Title under 8 words, text one sentence, a specific button label such as "Book a demo" rather than "Submit".

PropLabelTypeOptionsDefault
titleTitletext"Ready to get started?"
textTexttextarea"Tell the reader what happens next and why it is worth their time."
buttonLabelButton labeltext"Contact us"
buttonHrefButton linktext"#"

Cards

A grid of cards with title, text, optional link and image, in 2 to 4 columns.

AI hint: Use for features, benefits, services or a list of related pages. Three cards with parallel phrasing read best. Leave href empty when there is no target page.

PropLabelTypeOptionsDefault
cardsCardsarray[{"title":"First point","text":"Explain one benefit in a sentence or two.","href
cards[].titleTitletext
cards[].textTexttextarea
cards[].hrefLinktextplaceholder: /page or https://...
cards[].imageUrlImage URLtextplaceholder: /media/...
columnsColumnsradio2, 3, 43

Collection

A saved query (collection) of entities rendered as cards, a list or a grid, optionally with visitor filters (keyword, taxonomy, select, date range) and a pager; items are filled in by the server at render time.

AI hint: Use for "latest posts", "case studies" or any list that should update itself. Set collectionId to the key of an existing collection (ask or leave empty if unknown); never invent items, the server supplies them.

PropLabelTypeOptionsDefault
collectionIdCollection id or keytextplaceholder: latest_posts""
displayDisplayselect"cards", "list", "grid""cards"
columnsColumns (cards and grid)select2, 3, 43
showDateShow dateradiotrue, falsetrue
showSummaryShow summaryradiotrue, falsetrue
emptyTextText when emptytext"Nothing here yet."
filtersVisitor filtersarray[]
filters[].fieldField keytextplaceholder: department
filters[].labelLabeltext
filters[].kindKindselect"search", "taxonomy", "select", "daterange"
pageSizeItems per pagenumber (1..100)12
showPagerShow pagerradiotrue, falsefalse
showResultCountShow result countradiotrue, falsefalse

Calendar

A month grid or date list of the event occurrences in a collection, with a link to its iCal feed; filled in by the server at render time.

AI hint: Use on an events page. Set collectionId to the key of an existing collection of a type with a daterange field (ask or leave empty if unknown); view "month" for a grid, "list" for upcoming dates.

PropLabelTypeOptionsDefault
collectionIdCollection id or keytextplaceholder: upcoming_events""
viewViewradio"month", "list""month"
monthsAheadMonths shownnumber (1..12)1

Form

A lead-capture form defined under Forms in the admin, referenced by key. Fields, labels and the success message come from the definition.

AI hint: Use for contact, demo or newsletter forms. Set formKey to the key of an existing form (leave it empty if none is known); never invent fields here. Add a short title and a one-sentence intro.

PropLabelTypeOptionsDefault
formKeyForm keytextplaceholder: contact (from Forms in the admin)""
titleTitletext""
introIntro texttextarea""
submitLabelButton label overridetextplaceholder: Leave empty to use the form definition""

Shared

Label in the editor: Shared block.

A block saved in the component library (Shared blocks in the admin), referenced by key and rendered by the server; edit it once, update everywhere.

AI hint: Use only when the user names an existing shared block key (a promo, a contact card). Never invent keys; leave sharedKey empty if none is known.

PropLabelTypeOptionsDefault
sharedKeyShared block keytextplaceholder: from Shared blocks in the admin""

Personalize

Two slots, Default and Variant; visitors who match an audience (Audiences in the admin) see the variant. The server decides per visitor after the page loads, so pages stay cached.

AI hint: Use only when the user names an existing audience key. Put the content for everyone in "default" and the audience version in "variant"; keep both the same shape (a Hero in each, for example). Never invent audience keys.

PropLabelTypeOptionsDefault
audienceKeyAudience keytextplaceholder: from Audiences in the admin""
defaultDefault contentslotchild blocks[]
variantContent for the audienceslotchild blocks[]

Experiment

An A/B test: slots a (control), b and optional c; visitors of a running experiment (Experiments in the admin) are assigned a variant by weight and the results screen reports conversions per variant.

AI hint: Use only when the user names an existing experiment key. Put the current content in "a" and the challenger in "b"; leave "c" empty unless asked. Never invent experiment keys.

PropLabelTypeOptionsDefault
experimentKeyExperiment keytextplaceholder: from Experiments in the admin""
aVariant A (control)slotchild blocks[]
bVariant Bslotchild blocks[]
cVariant C (optional)slotchild blocks[]

RegistryBrowse

Label in the editor: Registry browse.

Search and browse the package registry (modules, themes, kits): a GET search form, kind tabs, a sort, result cards with badges and a pager; filled in by the registry service from the page URL. Placeholder on instances that do not host the registry.

AI hint: Use once on the /registry page of the project site. Keep the defaults; set kind to "theme" or "kit" only for a page dedicated to that kind. Needs no other props; the server supplies the results.

PropLabelTypeOptionsDefault
kindDefault kindselect"all", "module", "theme", "kit", "brand""all"
pageSizeResults per pagenumber (1..100)20
showSearchShow search boxradiotrue, falsetrue
showKindsShow kind tabsradiotrue, falsetrue
showSortShow sortradiotrue, falsetrue
layoutLayoutradio"list", "grid""list"
emptyTextText when nothing matchestext"No packages match. Try another word or a different kind."

RegistryPackage

Label in the editor: Registry package.

The detail page of one registry package, resolved from the last segment of the page path (/registry/<name>): header with badges, install command with a copy button, publisher and links, capability sheet, compatibility, versions, advisories, deprecation notice, README, changelog and a "For agents" section linking manifest.json.

AI hint: Use once on the /registry/<name> catch-all page of the project site. The package comes from the URL; there is nothing to fill in besides the section toggles.

PropLabelTypeOptionsDefault
basePathRegistry base pathtextplaceholder: /registry"/registry"
showReadmeShow READMEradiotrue, falsetrue
showVersionsShow versionsradiotrue, falsetrue
showChangelogShow changelogradiotrue, falsetrue
showAgentsShow "For agents" sectionradiotrue, falsetrue
notFoundTextText when the package is unknowntext"No package by that name. Check the spelling or search the registry."

RegistryStats

Label in the editor: Registry stats.

The registry totals: packages by kind, publishers and downloads, as a row of figures.

AI hint: Use on the registry landing or home page of the project site to show how much is published. Leave the title empty when a Heading precedes it.

PropLabelTypeOptionsDefault
titleTitle (optional)text""
showPublishersShow publishersradiotrue, falsetrue
showDownloadsShow downloadsradiotrue, falsetrue

ThemeGallery

Label in the editor: Theme gallery.

The theme directory: registry kits of kind "theme" as cards with a screenshot, description, publisher and Preview and Details links.

AI hint: Use on a /themes page of the project site. Set limit to the number of cards wanted; the server supplies the themes.

PropLabelTypeOptionsDefault
titleTitletext"Themes"
introIntro texttextarea"A theme is a kit of design tokens, blocks and page templates. Preview one on a
limitThemes to shownumber (1..60)12
columnsColumnsradio2, 33
showBrowseLinkLink to all themesradiotrue, falsetrue
emptyTextText when there are no themestext"No themes have been published yet."

PublisherProfile

Label in the editor: Publisher profile.

A publisher’s public profile (handle, name, verified badge, bio, website, maintainers) and their packages; the handle comes from the page path (/registry/publishers/<handle>) or the handle prop.

AI hint: Use once on the /registry/publishers/<handle> catch-all page of the project site, with handle left empty. Set handle only for a page about one known publisher.

PropLabelTypeOptionsDefault
handlePublisher handle (empty = from the URL)textplaceholder: acme""
basePathPublishers base pathtextplaceholder: /registry/publishers"/registry/publishers"
layoutPackage layoutradio"list", "grid""grid"
notFoundTextText when the publisher is unknowntext"No publisher by that handle."

OrgProfile

Label in the editor: Organization profile.

An organization’s public profile (handle, name, verified badge, website, members with their roles, the namespaces it owns) and the packages published under those namespaces; the handle comes from the page path (/registry/orgs/<handle>) or the handle prop.

AI hint: Use once on the /registry/orgs/<handle> catch-all page of the project site, with handle left empty. Set handle only for a page about one known organization.

PropLabelTypeOptionsDefault
handleOrganization handle (empty = from the URL)textplaceholder: acme""
basePathOrganizations base pathtextplaceholder: /registry/orgs"/registry/orgs"
layoutPackage layoutradio"list", "grid""grid"
showMembersList the membersradiotrue, falsetrue
notFoundTextText when the organization is unknowntext"No organization by that handle."

DocsFeedback

Label in the editor: Docs feedback.

"Was this page helpful?" with Yes and No buttons and an optional comment, posted to a form (docs_feedback by default) with the page path and the documented version as hidden fields; works without JavaScript and asks for no personal data.

AI hint: Put it last on a documentation page. Keep formKey at docs_feedback unless the site defines another feedback form; the docs kit creates that form and places this block on every doc page.

PropLabelTypeOptionsDefault
formKeyForm keytextplaceholder: docs_feedback"docs_feedback"
questionQuestiontext"Was this page helpful?"
yesLabelYes buttontext"Yes"
noLabelNo buttontext"No"
commentLabelComment labeltext"Tell us more (optional)"
thanksTextThanks texttext"Thanks for the feedback."
versionDocumented version (recorded with the answer)text""

StatusBoard

Label in the editor: Status board.

A list of Spillway instances with their state (up, degraded or down), version, when each was last checked and a 90-day uptime bar; the server fetches every instance’s /status.json (3 s timeout, cached for a minute) and reads the history the probe step records every five minutes.

AI hint: Use on a /status page of the project site. Fill instances with a name and the instance’s public URL (https://...); never invent URLs. Keep showUptime on unless asked.

PropLabelTypeOptionsDefault
titleTitle (optional)text"Status"
instancesInstancesarray[]
instances[].labelNametext
instances[].urlInstance URLtextplaceholder: https://www.example.org
showUptimeShow the 90-day uptime barradiotrue, falsetrue

Modules

ModuleBlock

Label in the editor: Module block.

A block an installed module provides (module name, block key and the block’s own props); rendered by the module on the server, with a placeholder when the module is disabled or missing.

AI hint: Only use with a module and block key that GET /api/builder/config lists; never invent one. Fill props from that block’s field definitions.

PropLabelTypeOptionsDefault
moduleModuletext""
blockKeyBlock keytext""
propsPropsobject{}

Spillway 0.1.0 · Edit this page on GitHub

Was this page helpful?