WebBlocks CMS Inventory for AI Page Building
Purpose
This is the compact, AI-facing design and authoring contract for WebBlocks CMS. Read it before proposing or applying a page design through the Internal Content API.
It answers five questions for every shipped core block:
- What content remains editable in the CMS admin?
- Which shared settings and variants are supported?
- Which child and media relationships are valid?
- What stable public HTML does the renderer emit?
- What visual result can the block produce without raw page HTML?
This document summarizes source-backed behavior. Live API discovery remains authoritative for install-specific IDs, enabled plugins, custom block types, locales, layouts, media records, navigation menus, and capabilities.
Audit Baseline
- Repository:
fklavyenet/webblocks-cms - Branch:
main - Audited commit:
741a44bc0fe00bf38cae0753bd9edb02978b0dbe - Audited release documentation:
1.40.2 - Audit date:
2026-07-14 - Repository shape: package-only Composer package
- Published core catalog rows:
51 - Draft legacy catalog rows:
7 - AI-writable structured core rows after the policy below is enforced:
50 - AI-writable raw HTML rows after the policy below is enforced:
0
Amendments since the audit
The baseline above is still the last full audit. These entries were corrected
against source afterwards rather than re-auditing every block, so treat anything
outside this list as 1.40.2-era and confirm it through live API discovery.
card (1.40.5): the Card style variant exists. This document previously
stated that no supported Card visual variant field existed, which was wrong
from 1.40.5 onward.link-list (1.40.10): settings.row_layout and settings.list_frame.link-list-item (1.40.8): optional media_id thumbnail.1.91.0: optional mobile-image relationships on eight native media blocks.1.91.1: all nine Slide and Slider content positions.1.93.0: Rich Text undo/redo, focus mode, word count, and safe paste behavior.1.94.0–1.94.2: managed-plugin startup validation, quarantine, retained packages, and active-account recovery checks.
Historical repository note: the pre-package-only CMS tree contained docs/feature-inventory.md, a broad product-feature discoverability matrix. It was removed when the package-only repository tree was constructed and was not a per-block AI authoring inventory. The runtime contract now lives at resources/contracts/inventory.md.
Source families inspected:
src/Support/Blocks/CoreBlockTypeCatalogSyncer.phpsrc/Support/BlockTypes/BlockTypeContractRegistry.phpsrc/Support/Blocks/BlockTranslationRegistry.phpsrc/Models/Block.phpsrc/Http/Requests/Admin/BlockRequest.phpsrc/Support/InternalContentApi/InternalContentPlanService.phpsrc/Support/InternalContentApi/InternalContentApiOperations.phpsrc/Http/Controllers/InternalContentApi/InternalContentResourceController.phpsrc/Http/Controllers/InternalContentApi/InternalSharedSlotController.phpsrc/Http/Controllers/InternalContentApi/InternalApiDiscoveryController.phproutes/admin.phpresources/views/admin/blocks/types/*.blade.phpresources/views/admin/blocks/settings/*.blade.phpresources/views/pages/partials/blocks/*.blade.phppublic/cms/css/public.css- focused package tests and current product documentation
Non-Negotiable AI Authoring Rules
- Use structured blocks. Do not store a page, section, card collection, navigation shell, form, or visual component in Trusted HTML.
html is a human-only escape hatch. API discovery may identify it as unavailable, but no API mutation may create, update, replace, move, reorder, clone, promote, publish, or delete an HTML block.- Do not bypass the HTML restriction through Rich Text,
<style>, <script>, event-handler attributes, iframe markup, SVG markup, encoded markup, or invented settings. - Use only fields, enum values, media roles, and child relationships documented here and confirmed by live discovery.
- Treat an admin-editable field as part of the supported authoring contract. A value recognized only by a renderer or legacy compatibility path is not a normal AI authoring field.
- If a visual region cannot be expressed with the supported contract, stop and report a capability gap. Do not silently approximate it with unrelated blocks and do not fall back to HTML.
- Site CSS may refine typography, spacing, color, borders, shadows, and responsive presentation through stable public hooks. It must not become a hidden content store or reconstruct missing semantic markup.
- Do not target database IDs, generated block IDs, sibling position selectors, or
:nth-child() for essential design behavior. Prefer block-type attributes, native wb-* classes, page body classes, and documented settings. - Keep every visible title, paragraph, label, button, badge, image, caption, menu, and form setting editable through its native CMS field or related record.
- Validate first, apply only after explicit user approval, create drafts first, and leave live system-update actions and live visual testing to the human operator unless separately authorized.
- Treat Card as opt-in presentation, not the default way to group related copy. Use a Card only for an independently actionable, repeatable, or bounded entity such as a product, plugin, price plan, download, or form.
- Before choosing blocks, state one site-level design direction covering character, density, typography, geometry, imagery, corners, and contrast. Make the block tree and site CSS implement that direction instead of choosing each section in isolation.
- Vary page rhythm deliberately. Combine narrow, regular, wide, and full-width regions; alternate quiet copy, dominant imagery, and structured collections rather than repeating equally weighted sections.
HTML Block API Policy
The target product contract is:
| Surface |
html behavior |
| CMS admin |
Human operators may create and edit reviewed Trusted HTML. |
| Public renderer |
Existing published HTML blocks continue to render. |
| API discovery |
Report the block as api_readable: true, api_writable: false, authoring: human_only, and explain the restriction. Do not present a writable payload example. |
| Content validate/apply |
Reject every new or replacement html payload with stable code block_type_not_api_writable. |
| Incremental page/shared-slot block create |
Reject html before normalization or persistence. |
| Existing block PATCH |
Reject when the target block type is html, even if the submitted field would otherwise be considered safe. |
| Reorder, move, delete, slot replacement, staged update, and promotion |
Reject any mutation whose affected subtree or replacement scope contains an existing HTML block. Do not delete it as a side effect. |
| API token capabilities |
No capability may override the product-level restriction. |
| Read endpoints |
May return the existing block for inspection according to the chosen read policy; read access must never imply write access. |
This policy is enforced in code by a single product policy class, WebBlocks\Cms\Support\BlockTypes\BlockTypeApiAuthoringPolicy. Every API surface consults it instead of repeating the rule: both block normalizers, existing-block PATCH, page and Shared Slot incremental create, page/Shared Slot reorder, subtree delete, Shared Slot clear-all, page and Shared Slot publish, draft slot replacement, staged update creation and promotion, Shared Slot assignment, and API page delete. Rejections happen before any transaction or write, return HTTP 422 with the stable code block_type_not_api_writable, and leave no partial changes. No token capability overrides it.
What “CMS-Manageable” Means
A design is CMS-manageable only when all of the following are true:
- Visible content is stored in native translation fields, settings, Media Library relations, Navigation records, Commerce records, or child blocks.
- The normal block editor exposes the fields needed to maintain the result.
- Public markup comes from a package or plugin renderer, not from page content.
- Presentation uses documented variants, settings, theme tokens, and stable CSS hooks.
- Reordering or editing content does not require editing HTML or CSS.
- Mobile behavior comes from the renderer, WebBlocks UI, or stable site CSS rather than duplicated mobile markup in content.
A renderer may recognize a legacy or internal value that the normal admin form does not expose. Such a value is documented as a compatibility input, not as a recommended AI authoring field.
Design Decision Table
| Visual need |
Preferred contract |
Stop condition |
| Major page band |
section with child blocks |
Do not put visible copy in Section settings. |
| Width constraint |
container |
Do not use Container as a card or surface. |
| Vertical content rhythm |
stack |
Do not use Container only to obtain vertical flow. |
| Main content plus a compact action or value |
split |
Use exactly two direct children; nest Stack when a side needs multiple blocks. |
| Horizontal actions or compact items |
cluster |
Do not use Grid for a single button row. |
| Responsive repeated cells |
grid with structured children |
Do not use Grid to fake a semantic table. |
| Page title, intro, badge, icon, metadata |
content_header |
It always owns an H1; do not use it for ordinary nested headings. |
| Marketing intro |
hero |
Hero supports left, centered, split, and full-bleed layouts; split renders foreground media while full-bleed creates an unframed photographic band. Report a gap when the design requires a second editable foreground image or arbitrary nested content. |
| Conversion band |
cta |
Current CTA does not accept normal structured children other than managed legacy button children. |
| Repeated feature or stat items |
columns and column_item |
Prefer grid and composable card when arbitrary nested content is needed. |
| Composable card |
card plus Card regions |
Use only for independently bounded/actionable content; variants are default, flat, muted, highlight, and accent. |
| Single semantic image |
image |
Use Gallery for collections and background media fields for supported backgrounds. |
| Image collection |
gallery |
Do not add a separate HTML lightbox. |
| Slider/carousel |
slider plus slide |
Use Gallery when the content is only an image collection. |
| Navigation |
Navigation records plus Navbar/Sidebar blocks |
Do not hardcode navigation anchors in HTML. |
| Contact form |
contact_form |
Do not use raw <form> markup or mailto: as the normal form. |
| Ratings/comments |
rating and comments |
Do not reproduce engagement storage or forms in HTML. |
| Unsupported one-off composition |
Capability-gap report |
Never default to html. |
Canonical Content-Plan Shape
Use nested children arrays. Do not submit database relationship IDs in a content plan.
{
"type": "section",
"settings": {
"spacing": "lg"
},
"children": [
{
"type": "container",
"settings": {
"width": "lg"
},
"children": [
{
"type": "plain_text",
"translations": {
"content": "Editable copy"
}
}
]
}
]
}
Content-plan conventions:
- Put locale-owned copy directly under
translations for the selected plan locale. - Put URL, target, presentation variant, and other shared options under
settings. - Put direct Media Library assignment in
media_id. slide, image, hero, section, card, cta, content_header, and
link-list-item also accept an optional top-level mobile_media_id referencing
an image Media Library record. It is stored in block_media with role
mobile_image, shared across locales, and editable through the admin media
picker and PATCH /blocks/{block}. On screens up to 768 px wide it replaces
the default image; an absent, deleted, or private mobile image falls back to
the default. Send null to clear it; omitting it in PATCH preserves it.
Foreground images use <picture><source media="(max-width: 768px)">;
background blocks use a responsive CSS background. Use another crop of the
same visual: alt text, captions, position, fit, overlays, and links stay
shared. The Image block's Gallery Viewer continues to open the default
full-resolution image. Gallery items, brand logos, video, and audio do not
accept this field.- Put Gallery items in
gallery_items or gallery_media_ids. - Use only nested
children; do not send id, parent_id, block_id, slot_type_id, or block_type_id. - The API currently accepts a broadly shaped
settings object. That permissiveness is not permission to invent settings; use only the keys listed below.
Public Rendering Shell
Normal main-slot rendering provides:
<main class="wb-public-main" id="main-content">
<div class="wb-container wb-container-lg">
<div class="wb-stack wb-gap-6">
<!-- page blocks -->
</div>
</div>
</main>
Blocks marked root-owning place data-wb-public-block-type on their own semantic root. Other top-level blocks normally receive:
<div class="wb-public-block" data-wb-public-block-type="block-handle">
<!-- renderer output -->
</div>
Underscores normalize to hyphens in data-wb-public-block-type; for example content_header becomes content-header.
Quick Catalog Index
The current published core catalog contains 55 rows:
| Group |
Handles |
| Layout and composition |
section, container, stack, split, cluster, grid, card, card_header, card_body, card_footer, slider, slide |
| Editorial and marketing |
header, plain_text, rich-text, content_header, hero, cta, columns, column_item, feature-grid, feature-item, stat-card, image, gallery, download, file, video, audio, code, button_link, table, quote, page-list, application |
| Navigation |
link-list, link-list-item, navigation-auto, toc, breadcrumb, header-actions, sticky-navbar, navbar-brand, navbar-navigation, sidebar-brand, sidebar-navigation, sidebar-nav-item, sidebar-nav-group, search-form, sidebar-footer |
| Pattern, form, and engagement |
alert, contact_form, rating, comments |
| Human-only advanced |
html |
Layout And Composition Blocks
section — Section
| Contract area |
Source-backed behavior |
| Purpose |
Major semantic page band and child grouping. |
| Admin-editable content |
No visible copy. Optional settings.layout_name is editor metadata only. |
| Settings |
spacing: empty, sm, lg; flow: normal, offset-up, overlap-previous; optional background media_id; background_position: center, top, bottom, left, right; background_overlay: soft, medium, strong, none. |
| Children |
Any supported published child type; at least one renderable child is required by API plans. |
| HTML |
Root-owning <section class="wb-section [wb-section-sm or wb-section-lg] [wb-public-section--offset-up or wb-public-section--overlap-previous] wb-stack" data-wb-public-block-type="section">…</section>. Background media adds package-owned class/style hooks. Flow modifiers reset on small screens. |
| Example appearance |
A full-width themed band containing a constrained Container, or one deliberately shifted band that breaks uniform vertical rhythm. |
| Avoid |
Visible text in settings, empty chrome, using Section as a card, or overlapping several consecutive sections. |
container — Container
| Contract area |
Source-backed behavior |
| Purpose |
Width constraint and optional child flow. |
| Admin-editable content |
No visible copy; optional editor-only layout_name. |
| Settings |
width: empty, sm, md, lg, xl, full; flow: stack or none. |
| Children |
Any supported published child type; at least one child required by API plans. |
| HTML |
Root-owning <div class="wb-container [wb-container-*] [optional wb-stack]" data-wb-public-block-type="container">…</div>; wb-stack requires explicit flow: stack. |
| Example appearance |
Centered page content with a maximum width; the neutral default composes directly with a Cluster inside Navbar. |
| Avoid |
Treating width as a surface, card, or theme role. |
stack — Stack
| Contract area |
Source-backed behavior |
| Purpose |
Vertical flow and consistent rhythm between direct child blocks. |
| Admin-editable content |
No visible copy; optional editor-only layout_name. |
| Settings |
spacing: empty/default, 1, 2, 3, 4, 6, 8. |
| Children |
Any supported published child type; at least one child required by API plans. |
| HTML |
Root-owning <div class="wb-stack [wb-stack-{n}]" data-wb-public-block-type="stack">…</div>. |
| Example appearance |
A product name, description, and supporting note arranged from top to bottom. |
| Avoid |
Page-width control, horizontal actions, or equal columns. |
split — Split
| Contract area |
Source-backed behavior |
| Purpose |
Two-sided composition where the first child grows and the second stays content-sized. |
| Admin-editable content |
No visible copy; optional editor-only layout_name. |
| Settings |
gap: empty/default, 0, 1, 2, 3, 4, 6, 8; items_alignment: center/default, start, end, stretch; width: auto/default or full; responsive: stack or preserve. New admin/API blocks default to stack while existing empty settings preserve the legacy row. |
| Children |
Exactly two direct children. Put a Stack inside either side when that side needs multiple blocks. |
| HTML |
Root-owning <div class="wb-split …" data-wb-public-block-type="split">…</div> with allowlisted wb-* classes. Responsive stack adds package-owned .wb-public-split--stack-mobile and changes to a full-width column at 48rem and below. |
| Example appearance |
Product identity on the left and a price plus buy action on the right. |
| Avoid |
Repeated equal columns, wrapping button groups, or more than two direct children. |
cluster — Cluster
| Contract area |
Source-backed behavior |
| Purpose |
Horizontal or inline composition, especially actions and navbar internals. |
| Admin-editable content |
No visible copy; optional editor-only layout_name. |
| Settings |
gap: empty, none, xs, sm, md, lg; alignment: start/default, center, end, between; items_alignment: center/default, start, end, stretch; wrap: wrap/default or nowrap; width: auto/default or full. |
| Children |
Any supported published child type; at least one child required by API plans. |
| HTML |
Root-owning <div class="wb-cluster …" data-wb-public-block-type="cluster">…</div> with allowlisted wb-* classes. |
| Example appearance |
A responsive two-button CTA row or brand/navigation/actions row. |
| Avoid |
Large repeated card grids. |
grid — Grid
| Contract area |
Source-backed behavior |
| Purpose |
Responsive multi-column layout. |
| Admin-editable content |
No visible copy; optional editor-only layout_name. |
| Settings |
columns: 2, 3, 4; ratio: equal, lead-left, lead-right (asymmetric ratios apply only to two columns); gap: empty, 3, 4, 6; alternate_media_text_sections: boolean; alternate_start: media_left or text_left. |
| Children |
Any supported published child type; at least one child required by API plans. |
| HTML |
Root-owning <div class="wb-grid wb-grid-{n} [wb-gap-{n}] [wb-public-grid--lead-*]" data-wb-public-block-type="grid">…</div>. Lead ratios render as 2:1 or 1:2 above the normal one-column mobile breakpoint. Alternating mode may change direct-child order without changing the root. |
| Example appearance |
Three Card blocks in a feature row, or paired Image/content groups alternating left and right. |
| Avoid |
Semantic tables or a compact action row. |
card — Card
| Contract area |
Source-backed behavior |
| Purpose |
Composable framed surface. |
| Admin-editable content |
No normal visible parent copy; optional editor-only layout_name. Legacy no-region Card rows may still render old copy. |
| Settings |
Optional Card style on the shared variant column: flat, muted, highlight, accent; an empty variant renders the default card. Optional background image media_id, background_position, background_overlay. Optional url and target make the entire composable Card one semantic link. |
| Children |
Direct children restricted to card_header, card_body, card_footer; at least one child required by API plans. |
| HTML |
Root-owning <article class="wb-card">…</article>, or <a class="wb-card wb-no-decoration">…</a> when a whole-card URL is configured. Linked Cards must not contain nested interactive controls. |
| Example appearance |
Image or icon header, editable body content, and action footer inside one native Card shell. |
| Avoid |
Cards nested inside Cards or using legacy parent copy for new content. |
| Contract area |
Source-backed behavior |
| Purpose |
Header region inside Card. |
| Admin-editable content |
No direct copy; child blocks hold content. Optional editor-only layout_name. |
| Settings |
icon_slug from the active content icon catalog; icon_tone: default, soft, brand, accent, highlight, bold, quiet; icon_size: default, sm, lg, xl. |
| Children |
Structured content children. Do not nest Card region blocks. Normal placement is directly under Card. |
| HTML |
Root-owning <div class="wb-card-header" data-wb-public-block-type="card-header">[icon]…</div>. |
| Example appearance |
Card title row with a catalog icon and nested Header/Plain Text. |
| Avoid |
Placement outside Card. |
card_body — Card Body
| Contract area |
Source-backed behavior |
| Purpose |
Main content region inside Card. |
| Admin-editable content |
No direct copy; child blocks hold content. Optional editor-only layout_name. |
| Settings |
No public visual setting beyond editor-only layout_name. |
| Children |
Structured content children; API plans require at least one. Do not nest Card region blocks. |
| HTML |
Root-owning <div class="wb-card-body" data-wb-public-block-type="card-body">…</div>. |
| Example appearance |
Card copy, Image, Rich Text, or a small Cluster of buttons. |
| Avoid |
Placement outside Card. |
| Contract area |
Source-backed behavior |
| Purpose |
Supporting or action region inside Card. |
| Admin-editable content |
No direct copy; child blocks hold content. Optional editor-only layout_name. |
| Settings |
No public visual setting beyond editor-only layout_name. |
| Children |
Structured content children; API plans require at least one. Do not nest Card region blocks. |
| HTML |
Root-owning <div class="wb-card-footer" data-wb-public-block-type="card-footer">…</div>. |
| Example appearance |
One or two Button Link children aligned by a nested Cluster. |
| Avoid |
Placement outside Card. |
slider — Slider
| Contract area |
Source-backed behavior |
| Purpose |
Composable carousel that fills its placed container. |
| Admin-editable content |
No visible parent copy; optional editor-only layout_name. |
| Settings |
height: auto, fill, viewport, large, medium, small, custom; optional min_height; aspect_ratio: 16/9, 4/3, 1/1; interval_ms: 1000–30000; booleans autoplay, pause_on_hover, show_arrows, show_dots, loop, swipe, keyboard; overlay: none/default, soft, medium, dark, strong; content_position: center/default, center-left, center-right, top-left, top-center, top-right, bottom-left, bottom-center, bottom-right; content_width: medium/default, narrow, wide, full; text_color: auto/default, light, dark; background_fit: cover/default or contain. Transition is currently normalized to slide. |
| Children |
Only slide; at least one Slide required. |
| HTML |
Root-owning <section class="wb-slider …" data-wb-slider data-wb-public-block-type="slider"> with viewport, track, optional arrows, and dots. |
| Example appearance |
Full-width hero carousel, card-contained slider, or background-media panels with editable child content. |
| Avoid |
Static image galleries. |
slide — Slide
| Contract area |
Source-backed behavior |
| Purpose |
One panel inside Slider. |
| Admin-editable content |
No direct visible copy; optional editor-only layout_name and shared aria_label. |
| Settings |
Background image media_id; background_position; background_overlay (none, soft, medium, strong — each renders a distinct scrim since WebBlocks UI 2.22.0; before that medium collapsed onto strong); content_position: center/default, center-left, center-right, top-left, top-center, top-right, bottom-left, bottom-center, bottom-right; content_width; text_color; background_fit. |
| Children |
Any supported structured child type; a background-only Slide is allowed. Normal parent is Slider. |
| HTML |
Root-owning <article class="wb-slide …" data-wb-public-block-type="slide">[img.wb-slide-media]<div class="wb-slide-content">…</div></article>. |
| Example appearance |
Background product photo with nested Header, Plain Text, and Button Link content. |
| Avoid |
Standalone top-level use when no carousel semantics are intended. |
Editorial And Marketing Blocks
| Contract area |
Source-backed behavior |
| Editable content |
translations.title. |
| Settings and variants |
settings.variant: h1–h6; alignment: left, center, right; anchor: safe same-page ID. |
| Children/media |
None. |
| HTML |
Root-owning <h1> through <h6> with optional alignment class and id. |
| Example appearance |
Semantic section heading that can be indexed by TOC. |
| Avoid |
Page intro with metadata; use Content Header. |
plain_text — Plain Text
| Contract area |
Source-backed behavior |
| Editable content |
translations.content as escaped plain text. |
| Settings and variants |
alignment: left, center, right. |
| Children/media |
None. |
| HTML |
Generic wrapper plus <p class="[wb-text-*]">…</p>. |
| Example appearance |
Short paragraph, label, or supporting sentence. |
| Avoid |
Lists, links, headings, or formatted body copy. |
rich-text — Rich Text
| Contract area |
Source-backed behavior |
| Editable content |
translations.content through the safe Rich Text editor and sanitizer; editor history supports undo/redo, with a word counter and optional focus mode. |
| Settings and variants |
None. Unsupported formatting, attributes, and classes are stripped; pasted headings and table cells retain their text as paragraphs, and executable/media markup is removed. |
| Children/media |
None. |
| HTML |
Generic wrapper plus <div class="wb-rich-text">[sanitized editorial markup]</div>. |
| Example appearance |
Several paragraphs with safe inline emphasis, links, and simple lists. |
| Avoid |
Layout markup, <style>, scripts, iframes, forms, buttons, tables, or a complete page. |
| Contract area |
Source-backed behavior |
| Editable content |
translations.title, translations.subtitle as intro, translations.eyebrow as optional badge label, translations.meta as metadata items. |
| Settings and variants |
alignment: left, center, right; icon_slug; icon_tone; icon_size: default, sm, lg, xl; badge_tone: neutral, info, success, warning, danger; optional background image and overlay settings. |
| Children/media |
No children; direct image media_id is background media. |
| HTML |
Root-owning <header class="wb-content-header …"> with optional icon/badge cluster, fixed <h1 class="wb-content-title">, subtitle, and metadata row. |
| Example appearance |
Page title with optional product badge/icon, concise lead text, and two metadata labels. |
| Avoid |
Nested sections where H1 is semantically wrong. |
hero — Hero
| Contract area |
Source-backed behavior |
| Editable content |
translations.title, translations.subtitle as eyebrow, translations.content. Action buttons are separate child button_link blocks with their own admin form. |
| Settings and variants |
variant: default, muted, soft, accent; layout: left, centered, split, or full-bleed; title_tag: h1, h2, h3; optional background image and overlay settings. |
| Children/media |
Actions are child button_link blocks, with no fixed count. In left/centered/full-bleed layouts media_id is background media; in split it renders as a foreground image beside the copy. |
| HTML |
Legacy layouts own <section class="wb-card wb-promo [wb-card-*]">; split adds .wb-promo--split and .wb-promo-media. Full-bleed deliberately drops the card class and uses .wb-public-hero--full-bleed with an aligned .wb-public-hero__copy. |
| Example appearance |
A contained promo, foreground image/copy split, or unframed viewport-wide photographic hero, plus actions. |
| Hard limitation |
No second foreground image, product-price/trust-strip region, or arbitrary nested content. |
| Actions |
Add button_link children; they render inside .wb-promo-actions. primary_cta / secondary_cta {label, url} objects remain accepted as a shorthand that writes the first two of those children. Do not reach for a sibling Cluster with Button Link — that renders outside the promo root. allowed_child_handles also lists legacy button, which has no published catalog row and stays in unreachable_child_handles. |
cta — CTA
| Contract area |
Source-backed behavior |
| Editable content |
translations.title, translations.subtitle as eyebrow, translations.content. Action buttons are separate child button_link blocks with their own admin form. |
| Settings and variants |
variant: default, muted, soft, accent; optional background image and overlay settings. CTA title renders as H2. |
| Children/media |
Actions are child button_link blocks, with no fixed count; direct image media_id is background media. |
| HTML |
Root-owning <section class="wb-card wb-promo [wb-card-*]"> with .wb-promo-copy and optional action row. |
| Example appearance |
Short conversion band near the end of a page. |
| Actions |
Identical to Hero: add button_link children, or use the primary_cta / secondary_cta shorthand. |
| Limitation |
settings.layout=centered is renderer-compatible but is not exposed by the normal CTA admin form and is not a recommended AI authoring field. |
columns — Columns
| Contract area |
Source-backed behavior |
| Editable content |
translations.title, translations.subtitle, translations.content; child item title, badge, content, URL, icon, and tones. |
| Settings and variants |
settings.variant: cards, plain, stats. New Internal Content API plans default an omitted variant to plain; cards must be deliberate. Existing stored blocks with an empty variant retain the legacy cards renderer fallback. |
| Children/media |
Only column_item. Child count selects stack, 2-column, 3-column, or 4-column layout. |
| HTML |
Root-owning <section class="wb-stack wb-gap-4"> with optional intro and a responsive item grid. |
| Example appearance |
Three benefit cards, four compact features, or a simple metric row. |
| Manageability caveat |
The stats renderer can use child subtitle as the value, but normal Column Item admin forms do not expose that subtitle. AI-created stats that depend on it are not fully manageable and should be avoided until the form contract is aligned. |
column_item — Column Item
| Contract area |
Source-backed behavior |
| Editable content |
translations.title, translations.content, optional translations.eyebrow badge; shared settings.url, icon_slug, icon_tone, icon_size, badge_tone. |
| Settings and variants |
Presentation is controlled by the parent Columns variant: cards, plain, or stats. |
| Children/media |
None; intended only under Columns. |
| HTML |
Cards: .wb-card > .wb-card-body; plain: .wb-icon-card; stats: .wb-stat. Optional safe link wraps cards/plain output. |
| Example appearance |
Icon-and-copy feature card with an optional badge. |
| Avoid |
Standalone use or relying on renderer-only subtitle for a stat value. |
Use plain for qualities, principles, benefits, process summaries, and other copy that does not represent independent objects. Use cards only when every item has a meaningful boundary of its own. The number of items — especially the familiar set of three — is never by itself a reason to choose cards.
feature-grid — Feature Grid
| Contract area |
Source-backed behavior |
| Editable content |
translations.title, subtitle, content; child feature fields. |
| Settings and variants |
No independent presentation variant. Renderer forces the Columns cards presentation and prefers three columns. |
| Children/media |
feature-item and compatibility column_item. |
| HTML |
Delegates to Columns and renders a card grid. It is not listed as root-owning by Block::ownsPublicRoot, so top-level output may receive a generic wrapper around the delegated Section root. |
| Example appearance |
Legacy three-up feature cards. |
| Recommendation |
For new pages prefer Columns/Column Item or Grid/Card; use Feature Grid only when its dedicated editor is valuable and the delegated contract is accepted. |
feature-item — Feature Item
| Contract area |
Source-backed behavior |
| Editable content |
translations.title, translations.content, optional badge label; shared URL, icon slug/tone, badge tone. |
| Settings and variants |
Always delegates to Column Item cards presentation. |
| Children/media |
None; intended under Feature Grid. |
| HTML |
.wb-card > .wb-card-body > .wb-icon-card with optional icon and badge. |
| Example appearance |
One icon-led feature card. |
| Recommendation |
Prefer canonical Card regions or Column Item for new general-purpose compositions. |
stat-card — Stat Card
| Contract area |
Source-backed behavior |
| Editable content |
translations.subtitle label, translations.title value, translations.content detail; shared URL. |
| Settings and variants |
None. |
| Children/media |
None. |
| HTML |
Generic wrapper plus .wb-stat, .wb-stat-label, .wb-stat-value, .wb-stat-meta, and optional Learn more link. |
| Example appearance |
“24h” value with “Dispatch” label and supporting detail. |
| Avoid |
Decorative marketing card where arbitrary nested content is needed. |
image — Image
| Contract area |
Source-backed behavior |
| Editable content |
Locale-owned image alt_text and caption; shared optional URL. |
| Settings and variants |
viewer_enabled opts an unlinked image into the CMS Gallery Viewer; viewer_group joins independently placed Image blocks into one browsable viewer set. Focal point and generated variants belong to the Media record. |
| Children/media |
Direct image media_id; no children. |
| HTML |
Root-owning <figure class="wb-stack wb-gap-2"> with responsive <img> output, optional linked or wb-gallery-trigger image, and <figcaption>. Enabled groups register one existing gallery-viewer modal under the canonical overlay root. |
| Example appearance |
Product or editorial image with an editable caption. |
| Avoid |
Background treatment or decorative layout HTML. Use Gallery when the collection itself should render as one grid; use viewer groups when independently composed images should share one viewer without changing layout. |
gallery — Gallery
| Contract area |
Source-backed behavior |
| Editable content |
Ordered Gallery items with locale-owned alt_text, caption, overlay_title, overlay_text; optional shared viewer title. Gallery intro copy is intentionally separate. |
| Settings and variants |
variant: grid, masonry, collage; columns: 2–5; gap: none, sm, md, lg; aspect_ratio: auto, square, 4:3, 16:9, portrait; captions_mode: hidden, below, overlay, on-hover; overlay_mode: none, gradient, solid; lightbox_enabled: boolean. |
| Children/media |
gallery_items or gallery_media_ids referencing image Media records; no block children. |
| HTML |
Root-owning .wb-gallery.wb-gallery--{variant} with gallery items, responsive media, captions, and optional registry-owned viewer under the canonical overlay root. |
| Example appearance |
Equal product grid, natural-height editorial masonry, or featured-first collage. |
| Avoid |
Adding heading/description into Gallery; compose Content Header or Rich Text before it. |
download — Download
| Contract area |
Source-backed behavior |
| Editable content |
translations.title button label and translations.subtitle helper copy. |
| Settings and variants |
settings.variant: primary, secondary, ghost. |
| Children/media |
Direct document/other media_id; no children. |
| HTML |
Root-owning .wb-stack.wb-gap-2 with <a class="wb-btn …" download> and optional helper paragraph. |
| Example appearance |
“Download guide” button with file description. |
| Avoid |
External-only file cards; use File. |
file — File
| Contract area |
Source-backed behavior |
| Editable content |
translations.title, translations.content; shared URL fallback. |
| Settings and variants |
None. |
| Children/media |
Direct document/other media_id; media wins over safe external URL. |
| HTML |
Root-owning muted Card with title, description, download/open button, and file metadata. |
| Example appearance |
Downloadable PDF resource card. |
| Avoid |
Simple button-only downloads. |
video — Video
| Contract area |
Source-backed behavior |
| Editable content |
translations.title, translations.content; shared safe URL fallback. |
| Settings and variants |
Source determines native video, YouTube/Vimeo iframe, or open-video button. |
| Children/media |
Direct video media_id; no children. |
| HTML |
Root-owning muted Card containing <video>, an allowlisted provider <iframe>, or a safe link. |
| Example appearance |
Uploaded demo video with editable title and description. |
| Avoid |
Arbitrary iframe HTML. |
audio — Audio
| Contract area |
Source-backed behavior |
| Editable content |
translations.title, translations.content; shared safe HTTP URL fallback. |
| Settings and variants |
None. |
| Children/media |
Admin and renderer support selected audio media; no children. |
| HTML |
Root-owning muted Card with copy and native <audio controls>. |
| Example appearance |
Audio lesson or sample player. |
| API gap |
The audited content-plan direct-media allowlist omits audio, so media_id assignment is rejected even though the admin and renderer support it. Use a reviewed safe URL only when appropriate or fix the API contract before AI media assignment. |
code — Code
| Contract area |
Source-backed behavior |
| Editable content |
translations.title, translations.subtitle filename/language label, translations.content code body. |
| Settings and variants |
settings.language becomes sanitized data-language. |
| Children/media |
None. |
| HTML |
Generic wrapper plus <pre><code data-language="…">…</code></pre>. |
| Example appearance |
Copyable-looking command or source snippet. |
| Avoid |
Prose, layout, or executable scripts. |
| Contract area |
Source-backed behavior |
| Editable content |
translations.title as the button label; shared settings.url. At public render time an internal path follows the render locale (rewritten to the target page's translated path when it resolves); the stored value stays shared and raw. |
| Settings and variants |
settings.target: _self or _blank; shared variant: primary/default or secondary. URL accepts a safe full HTTP(S) URL, site path, anchor, mailto:, or tel: target. |
| Children/media |
None. This is a standalone editorial action and is distinct from the non-catalog managed button child used by Hero and CTA. |
| HTML |
Generic wrapper plus <a class="wb-btn wb-btn-primary"> or its secondary-class equivalent; _blank adds rel="noopener noreferrer". Empty or unsafe URL emits no anchor. |
| Example appearance |
One managed primary or secondary action, or several actions arranged by a Cluster. |
| Avoid |
Hardcoded anchors in HTML or substituting it for Hero/CTA's internal managed-action child when the action must render inside that promo root. |
table — Table
| Contract area |
Source-backed behavior |
| Editable content |
translations.title; translations.content as newline-separated, pipe-delimited rows. |
| Settings and variants |
settings.variant: header-row/default or plain. Legacy settings.rows remains readable but is not recommended for new API content. |
| Children/media |
None. |
| HTML |
Generic wrapper containing .wb-table-wrap > table.wb-table, optional <thead>, and <tbody>. |
| Example appearance |
Small comparison or specification table. |
| Avoid |
Page layout grids or interactive datasets. |
quote — Quote
| Contract area |
Source-backed behavior |
| Editable content |
translations.content quote, translations.title and translations.subtitle attribution parts. |
| Settings and variants |
settings.variant: default or testimonial. |
| Children/media |
None. |
| HTML |
Generic wrapper with <blockquote class="wb-stack wb-gap-2">; testimonial adds a muted Card shell. |
| Example appearance |
Editorial quotation or customer testimonial. |
| Avoid |
General-purpose callouts. |
Navigation Blocks
link-list — Link List
| Contract area |
Source-backed behavior |
| Editable content |
translations.title, translations.subtitle, translations.content; child link copy. |
| Settings and variants |
settings.row_layout: index (default), stacked puts each row description under its title. settings.list_frame: joined (default), cards gives each row its own card. Independent; both are writable through the API. |
| Children/media |
Only link-list-item. |
| HTML |
Generic wrapper with optional intro stack and .wb-link-list, plus wb-link-list--stacked / wb-link-list--cards for the selected styles. |
| Example appearance |
Resource index with title, metadata, description, icons, and badges. |
link-list-item — Link List Item
| Contract area |
Source-backed behavior |
| Editable content |
Required translations.title, optional subtitle, content, and eyebrow badge; shared required URL. |
| Settings and variants |
icon_slug, icon_tone, icon_size, badge_tone. |
| Children/media |
Optional image media_id thumbnail; intended under Link List. |
| HTML |
<a class="wb-link-list-item"> with an optional leading thumbnail or icon (adding wb-link-list-item--media), title/meta/badge, and optional description. |
| Example appearance |
Documentation/resource row marked “New”. |
| Render guard |
Emits only with both a safe URL and title. |
page-list — Page List
| Contract area |
Source-backed behavior |
| Editable content |
No page copy. Titles, descriptions, and thumbnails come from each listed page's translation: name, then list_excerpt falling back to seo_description, then og_image_media_id. |
| Settings and variants |
scope (page_type, path_prefix, subtree_of_current), page_type, path_prefix, sort, limit (1-48), layout (cards/links), columns, show_thumbnail, show_description, exclude_current, clickable_card. |
| Children/media |
Neither. Rows come from a page query; thumbnails resolve from each page translation's Open Graph image. |
| HTML |
wb-grid of wb-card articles (or single-link Card roots when clickable_card is enabled), or a wb-link-list of wb-link-list-item anchors. |
| Example appearance |
A three-column index of guide cards, each linking from its title. |
| Render guard |
Emits nothing when the query returns no pages, or while the scope is unconfigured. Published status, site, render-locale translation, Shared Slot source pages, and the hosting page are filtered in the query and are not settings. |
application — Application Block
| Contract area |
Source-backed behavior |
| Editable content |
No editorial copy. Selects a database-registered Embedded Application by stable application_handle. |
| Settings and variants |
application_settings is validated against the selected definition schema. CMS-owned presentation settings are width, loading, aspect_ratio, min_height, show_loading_state, and show_failure_state. |
| Children/media |
Neither. Executable assets belong to the registered application definition and cannot be supplied through block content or Media. |
| HTML |
Inline applications receive a generated .wb-application__mount; iframe applications receive a CMS-owned, sandboxed iframe. CSS and JavaScript declared by ready definitions load once per page. |
| API authoring |
Writable through content validate/apply and direct block settings patch. Discover handles with GET /webadmin/api/applications and schemas with /applications/{application}/schema; these reads require applications.read. Registry mutation is not exposed. |
| Render guard |
Missing, invalid, or duplicate definitions do not load assets or execute. They render nothing unless the block's translated generic failure state is enabled. |
navigation-auto — Navigation Auto
| Contract area |
Source-backed behavior |
| Editable content |
No page copy; selected CMS Navigation menu. |
| Settings and variants |
menu_key from known menu locations. Footer/legal keys render stacked links; primary/default renders clustered button-style links. |
| Children/media |
Navigation records, not block children. |
| HTML |
Generic wrapper plus semantic <nav> and <ul> tree. |
| Example appearance |
Compatibility navigation menu in a slot. |
| Recommendation |
Prefer Navbar Navigation for new shared headers. |
| Contract registry gap |
This published handle has an admin form and renderer but no entry in BlockTypeContractRegistry at the audit baseline. Do not infer a complete live API contract until discovery confirms it. |
toc — TOC
| Contract area |
Source-backed behavior |
| Editable content |
Optional shared title. |
| Settings and variants |
None. |
| Children/media |
Reads published Header blocks in the same slot with valid anchors and H2/H3 variants, in document order. |
| HTML |
Generic wrapper with a generated nav.wb-section-nav link list — a self-contained WebBlocks UI primitive, not wb-link-list. |
| Live behavior |
Scroll-position highlighting comes free from the shipped WBSectionNav module in the same webblocks-ui.js the public layout already loads; the renderer owns no JavaScript of its own. |
| Example appearance |
“Contents” list for a long documentation page. |
| Render guard |
Emits nothing when no eligible headings exist. |
breadcrumb — Breadcrumb
| Contract area |
Source-backed behavior |
| Editable content |
Shared home_label; current page title comes from the page. |
| Settings and variants |
include_current: boolean. |
| Children/media |
Uses page/site/locale context. |
| HTML |
Generic wrapper plus <nav class="wb-breadcrumb"><ol class="wb-breadcrumb-list">…</ol></nav>. |
| Example appearance |
Home / Category / Current page. |
| Contract area |
Source-backed behavior |
| Editable content |
No copy. |
| Settings and variants |
Booleans show_search, show_mode_toggle, show_accent_toggle, show_language_switcher. Public preset/accent controls are currently suppressed by the site-level Public Theme model. |
| Children/media |
None. |
| HTML |
Generic wrapper plus compact .wb-topbar-actions icon controls. |
| Example appearance |
Search and light/dark/auto mode actions at the right side of a Navbar. |
| Avoid |
Business CTAs. |
sticky-navbar — Navbar
| Contract area |
Source-backed behavior |
| Editable content |
No direct copy; optional editor-only layout_name. |
| Settings and variants |
sticky_mode: sticky/default, static, fixed. |
| Children/media |
Allowed children: container, cluster, header, plain_text, rich-text, button_link, navbar-brand, navbar-navigation, header-actions, search-form. At least one child required by API plans. |
| HTML |
Root-owning <nav class="wb-navbar …" data-wb-public-block-type="sticky-navbar">…</nav>. |
| Example appearance |
Shared header: Navbar → Container → Cluster(between) → Brand + navigation/actions. |
| Avoid |
A second custom header shell. |
navbar-brand — Navbar Brand
| Contract area |
Source-backed behavior |
| Editable content |
translations.title, translations.subtitle; shared URL, target, aria label. |
| Settings and variants |
url; target: _self or _blank; aria_label. |
| Children/media |
Optional image media_id for logo. |
| HTML |
Generic wrapper plus <a class="wb-navbar-brand"> with optional image and identity copy. |
| Example appearance |
Logo, site name, and concise tagline. |
navbar-navigation — Navbar Navigation
| Contract area |
Source-backed behavior |
| Editable content |
Shared title as ARIA label; selected Navigation menu. |
| Settings and variants |
menu_key; active_indicator: underline, pill, dot, background, none; active_matching: path, section, current-page, exact, off. |
| Children/media |
CMS NavigationItem tree. |
| HTML |
Generic wrapper plus desktop .wb-navbar-links, mobile WebBlocks UI dropdown, active classes, and group dropdowns. |
| Example appearance |
Responsive primary navigation with automatic burger menu. |
| Contract area |
Source-backed behavior |
| Editable content |
translations.title, translations.subtitle; shared URL, target, aria label. |
| Settings and variants |
Same safe link contract as Navbar Brand. |
| Children/media |
Optional image media_id for logo. |
| HTML |
Generic wrapper plus <a class="wb-sidebar-brand"> with logo and identity copy. |
| Example appearance |
Documentation logo/title at the top of a sidebar. |
| Contract area |
Source-backed behavior |
| Editable content |
translations.title as ARIA label; optional editor-only layout_name. |
| Settings and variants |
Optional menu_key; show_icons: boolean; active_matching: path, current-page, exact. |
| Children/media |
Either CMS Navigation records or manual sidebar-nav-item / sidebar-nav-group; at least one child is required in manual API plans. |
| HTML |
Generic wrapper plus <nav class="wb-sidebar-nav"> and WebBlocks UI sidebar structures. |
| Example appearance |
Documentation sidebar with active section indication. |
| Contract area |
Source-backed behavior |
| Editable content |
Required translations.title; shared URL and target. |
| Settings and variants |
icon from catalog; active_mode: exact, path, current-page, manual; manual_active: boolean. |
| Children/media |
None; intended under Sidebar Navigation or Sidebar Nav Group. |
| HTML |
<a class="wb-sidebar-link"> or nested .wb-nav-group-item, with optional icon and active state. |
| Example appearance |
Manual documentation link. |
| Contract area |
Source-backed behavior |
| Editable content |
Required translations.title; optional editor-only layout_name. |
| Settings and variants |
icon; initially_open: boolean. |
| Children/media |
Only sidebar-nav-item. |
| HTML |
.wb-nav-group with button toggle, arrow, icon, and .wb-nav-group-items. |
| Example appearance |
Collapsible “Guides” group in a docs sidebar. |
| Contract area |
Source-backed behavior |
| Editable content |
translations.title label, translations.content placeholder, translations.subtitle submit label. |
| Settings and variants |
settings.variant: primary or secondary; show_button: boolean. |
| Children/media |
None; requires a resolvable site search route. |
| HTML |
Generic wrapper plus <form role="search" class="wb-cluster …">, native input, and optional WebBlocks button. |
| Example appearance |
Site search field in a header or page. |
| Contract area |
Source-backed behavior |
| Editable content |
translations.title, translations.content, translations.subtitle footer note. |
| Settings and variants |
settings.variant: info, success, warning, danger. |
| Children/media |
None. |
| HTML |
Generic wrapper plus .wb-sidebar-footer, toned .wb-callout, and optional muted note. |
| Example appearance |
Small documentation notice or version note. |
alert — Alert
| Contract area |
Source-backed behavior |
| Editable content |
translations.title, required translations.content. |
| Settings and variants |
settings.variant: info, success, warning, danger. |
| Children/media |
None. |
| HTML |
Generic wrapper plus <div class="wb-alert wb-alert-{tone}"> and optional title. |
| Example appearance |
Inline warning, success note, or informational message. |
| Avoid |
Marketing promos. |
| Contract area |
Source-backed behavior |
| Editable content |
Locale-owned title, content, submit_label, success_message, consent_label. |
| Settings and variants |
recipient_email; send_email_notification; store_submissions remains product-owned true in the native contract; consent_required (boolean, default false). |
| Consent |
Set consent_required and give the locale a consent_label to render a required consent checkbox. The wording is translated because it is the notice. An accepted submission stores consent_accepted_at plus a copy of the wording, so editing the block later cannot change what a past visitor is recorded as having agreed to. A required consent with no wording for the resolved locale renders no checkbox rather than an unlabelled one. consent_required is closed to PATCH: removing a legal notice from a live form is an operator decision. |
| Children/media |
None. |
| HTML |
Generic wrapper around native section.wb-card, CSRF-protected form, renderer-generated anti-spam field, WebBlocks inputs, textarea, optional consent checkbox, validation errors, and submit button. |
| Example appearance |
Fully managed contact form stored in Contact Messages with optional notification. |
| Avoid |
Raw form HTML, custom honeypot fields, or mailto: replacement. |
rating — Rating
| Contract area |
Source-backed behavior |
| Editable content |
Optional shared single-language settings.title; normal visitor copy is product-translated. |
| Settings and variants |
scale: fixed 5; allow_change: boolean; show_summary: boolean. |
| Children/media |
Uses content_ratings; no children. |
| HTML |
Root-owning <section class="wb-card"> with optional H3, partially filled .wb-rating-stars, summary, and no-JS .wb-rating-input submit buttons. |
| Example appearance |
Five-star page rating with average and response count. |
| Note |
allow_change is enforced by the submission controller rather than by hiding the form. |
| Contract area |
Source-backed behavior |
| Editable content |
No block-authored visitor copy; product translations supply labels and messages. |
| Settings and variants |
form_enabled, show_approved, show_author_name; sort_order: newest or oldest. |
| Children/media |
Uses moderated comment_entries; no children. |
| HTML |
Root-owning <section class="wb-card wb-public-comments"> with approved comment list, native CSRF form, anti-spam field, validation state, and submit action. |
| Example appearance |
Moderated comments below an article or product guide. |
| Avoid |
Custom comment storage or raw form markup. |
Human-Only Advanced Block
html — HTML (Trusted)
| Contract area |
Source-backed behavior and target policy |
| Purpose |
Reviewed human escape hatch for trusted markup that has no structured product contract yet. |
| Admin-editable content |
Trusted HTML content. The current translation registry treats it as text-family content. |
| Settings and variants |
None. Recognized overlay/body-end fragments may be extracted to package registries. |
| Children/media |
No children. |
| HTML |
Generic wrapper plus a plain inner <div> containing trusted markup; extracted fragments may render outside the visible root. |
| API authoring |
Prohibited. No create, update, replacement, topology mutation, destructive mutation, staged mutation, or publish mutation. |
| AI behavior |
Report a capability gap and propose a structured block/variant/renderer. Never generate a writable HTML payload. |
Legacy And Renderer-Only Handles
Do not treat a Blade partial as proof that a handle is available for new API content. The current source contains compatibility renderers and draft rows that are not published core authoring contracts.
Draft catalog rows include:
text
card-grid
tabs
menu
faq-list
showcase-list
contact-info
Renderer-only, alias, partial, or compatibility handles include examples such as:
accordion
faq
button
callout
list
map
metric-card
stats
testimonial
gallery-viewer
sidebar-nav-item-link
sidebar-navigation-menu-item
fallback
missing-renderer
Rules:
- Never author these merely because a renderer file exists.
- Use them only if the live authenticated block catalog reports the exact handle as published and usable for the current install.
- Prefer canonical structured blocks documented above.
- Internal partials such as gallery viewer and sidebar link renderers are never content-plan block types.
Visual Composition Recipes
These are managed block trees, not fixed templates. Confirm all handles at runtime.
Start from the least framed recipe that satisfies the content. Do not repeat the same recipe in adjacent page bands, and do not select the feature-card recipe merely because the source contains three short items.
section(spacing:lg)
└── container(width:xl)
└── hero(layout:split, foreground media)
├── button_link(primary)
└── button_link(secondary)
Use a large, meaningful image and restrained surface styling. Choose layout:full-bleed when the image should become a viewport-wide, unframed opening band; retain split when the image is semantic foreground content.
Unframed principles or benefits
section(spacing:lg)
└── container(width:xl)
└── columns(variant:plain)
├── column_item
├── column_item
└── column_item
This is the normal starting point for qualities such as experience, communication, care, speed, or reliability. Promote it to Cards only when the items are independently actionable or bounded.
Marketing page intro with separate actions
section(background optional)
└── container(width:lg)
├── hero(variant:accent, layout:centered)
└── cluster(alignment:center, gap:sm)
├── button_link(primary)
└── button_link(secondary)
Use this only when the action row should sit outside the Hero promo root. Hero itself accepts Button Link children in every layout, including split; keep actions inside Hero when that is the intended composition.
Bounded entity card grid
section(spacing:lg)
└── container(width:lg)
├── header(h2)
└── grid(columns:3, gap:4)
├── card
│ └── card_body
│ ├── header(h3)
│ ├── plain_text
│ └── button_link
├── card
└── card
Every title, paragraph, and action remains independently editable. Reserve this recipe for bounded entities such as products, plugins, plans, downloads, or services with their own actions. Use site CSS for a consistent site-specific Card skin through stable hooks; do not inject card HTML.
Alternating image and copy rows
section
└── container
├── grid(columns:2, alternate_media_text_sections:true, alternate_start:media_left)
│ ├── image
│ └── card or content stack
└── grid(columns:2, alternate_media_text_sections:true)
├── image
└── card or content stack
Use Image for foreground media. Use a background-capable block only when the image is semantically a background.
Shared responsive navbar
sticky-navbar(sticky)
└── container(width:lg)
└── cluster(alignment:between, width:full)
├── navbar-brand
└── cluster
├── navbar-navigation
└── header-actions
Navigation labels and URLs belong to CMS Navigation records, not to HTML.
Managed image slider
slider(height:viewport, autoplay:false, show_arrows:true, show_dots:true)
├── slide(background media)
│ └── container
│ ├── header
│ ├── plain_text
│ └── button_link
└── slide(background media)
└── container
└── card
└── card_body
└── rich-text
Design-To-CMS Workflow
Before applying a visual design, produce a mapping table:
| Design region |
Content owner |
Block tree |
Variant/settings |
Stable CSS hooks |
Capability status |
| Example hero |
Page translations and Media Library |
Section → Container → Hero |
accent, centered, background media |
[data-wb-public-block-type="hero"], .wb-promo |
Supported only if background-media promo matches the design |
For each region:
- Identify every editable piece of copy, media, action, badge, navigation data, and dynamic record.
- Map each piece to an admin-editable native field.
- Confirm parent/child rules and renderer HTML.
- Confirm the visual composition is possible with the documented DOM.
- Use site CSS only for presentation that the stable DOM can support.
- If any semantic field, wrapper, slot, or variant is missing, mark the region unsupported.
- Propose the smallest reusable CMS or plugin capability: a renderer variant, a new structured block, a pattern composed of existing blocks, or a domain block such as a Commerce product collection.
- Do not apply a knowingly low-fidelity substitute unless the user explicitly approves that compromise.
Capability-gap report format:
Region: Storefront hero
Required editable content: title, body, two actions, foreground product image, offer badge, trust items
Current closest block: hero
Supported: title, eyebrow, body, background image, promo tone
Missing: foreground media slot, split DOM, trust-item collection, discoverable managed action child
Why CSS is insufficient: required semantic wrappers and editable fields do not exist
Recommended product change: add a reusable split/storefront Hero variant and structured trust-item children
HTML fallback: prohibited
CSS Guidance
Use styling layers in this order:
- WebBlocks UI primitives already emitted by the renderer.
- Public Theme tokens and mode-aware public color roles.
- Native block settings and variants.
- Narrow site-specific CSS using stable hooks.
- A reusable renderer or block contract change when the required DOM is missing.
Stable selectors include:
body[data-wb-public-theme] {}
[data-wb-public-block-type="hero"] {}
[data-wb-public-block-type="card"] {}
.wb-promo {}
.wb-card {}
.wb-content-header {}
Do not use site CSS to:
- insert essential text with pseudo-elements;
- depend on generated block IDs;
- infer semantics from sibling order;
- hide CMS-authored content merely to replace it with CSS content;
- rebuild a missing layout with fragile absolute positioning;
- hardcode light-only colors that break Light/Dark/Auto mode.
Known Source Gaps At The Audit Baseline
These are implementation findings, not permissions to invent behavior:
- Resolved: this inventory now ships as
resources/contracts/inventory.md and is served to tools by GET /webadmin/api/inventory. webblocks-cms-docs/docs/block-type-contracts.md says 42 published core types, while the current catalog defines 51.- Several existing docs still show pre-package-only renderer paths under
packages/webblocks-cms/...; current package paths begin at resources/views/.... - Resolved: Trusted HTML is no longer API-writable.
BlockTypeApiAuthoringPolicy blocks every API mutation path, including generic normalization, existing-block PATCH, and the Shared Slot reorder, subtree-delete, clear-all, and publish operations. - Resolved: Hero and CTA are plain containers for
button_link children in both the admin and the API. The primary_cta / secondary_cta fields survive as a two-button shorthand. The unpublished legacy button catalog row is no longer an authoring blocker. - Resolved: the Column Item editor now exposes the subtitle field that the Columns
stats variant renders as the stat value. - Audio has a normal admin media picker and public media renderer, but the content-plan direct-media allowlist omits Audio.
- Resolved: icon normalization has one owner.
InternalContentApiOperations holds the canonical PUBLIC_ICON_BLOCK_TYPES list plus the shared slug/tone normalizers, and the full content plan delegates to them, so plans and incremental block endpoints validate icons identically. - API block settings are not yet governed by one per-block machine-readable settings schema. Unknown settings can survive normalization even when no renderer or admin field uses them.
- Resolved:
navigation-auto now has a documented contract in BlockTypeContractRegistry and is discoverable through block-types and content-contract. - WebBlocks UI ships a
wb-footer-* anatomy (wb-footer-grid, wb-footer-brand, wb-footer-nav, wb-footer-link, wb-footer-list, wb-footer-item, wb-footer-copy, wb-footer-meta, wb-footer-text, wb-footer-logo) that no CMS renderer emits. A shared-slot footer composes generic wb-section/wb-container/wb-grid/wb-stack/wb-cluster instead, so the pattern is reachable only from hand-written layouts. Cosmetic since 1.50.0 gave .wb-slot-footer its own surface; a footer-composition block remains deliberately deferred rather than pending. - Resolved:
GET /content-contract derives its media_library section from the registered route table, so supported_operations and unsupported_operations cannot drift from what openapi.json publishes. Upload, remote fetch, delete, replace and move are published as supported with the capability each route enforces. - Resolved: consent has a visitor-facing half. The System Settings banner toggle renders WebBlocks UI's Cookie Consent pattern on public pages and wires it to the existing
POST /privacy-consent/sync endpoint, and contact_form gained settings.consent_required plus a translated consent_label recorded on each submission. - The repository has dashboard and page-management screenshots, but no canonical per-block/per-variant visual fixture gallery. The “Example appearance” descriptions in this inventory are therefore source-derived, not screenshot-backed golden references. Until that gallery exists, prefer documented neutral compositions and avoid claiming visual fidelity from prose alone.
- Resolved for planning:
GET /content-contract now publishes a machine-readable design-direction contract covering character, density, typography, geometry, imagery, corners, contrast, rhythm roles, Card policy, and known composition gaps. It deliberately does not persist a hidden style record; AI tools state the direction in their plan/report and implement it through supported block choices, theme tokens, and stable site CSS.
Inventory Review And Freshness Checks
The product owns this runtime contract. The documentation repository keeps a generated version snapshot with a distinct source identity; edits start in the product contract.
From CMS 1.94.3, composer test:inventory and composer test:docs validate resources/contracts/inventory-review.json against the current contract and runtime source fingerprints. Changed, added, or removed runtime files and product version changes require a new explicit review. CI and pre-push run the same check; release preparation checks the working tree, and the artifact builder checks the selected Git tree.
After reviewing supported fields, enums, children, media, rendering, editor behavior, permissions, and plugin lifecycle, update this prose and record the review with composer inventory:review -- --reviewed --note="review summary". An unchanged contract after a source change is accepted only with an explicit --no-authoring-impact="reason" explanation. Review records must never be refreshed automatically by CI or release scripts.
The mechanical record captures the published core catalog, child rules, renderer-root ownership, API write policy, and mobile-media support from actual product helpers. PHPUnit compares this record with the current helpers, and the source check requires a unique inventory heading for every published core block. Fingerprints and mechanical comparisons enforce review and structural consistency; they do not prove every sentence's meaning. Prose and no-impact explanations remain the contributor's and reviewer's responsibility.
The documentation repository's tools/inventory-snapshot.php regenerates the snapshot and its inventory-source.json provenance. Its checks reject manual snapshot edits and compare product version, source fingerprint, review checksum, and document content against a selected product checkout. Isolated documentation checks verify recorded provenance without requiring the product at runtime. Snapshot generation and CMS publication remain separate operations.
webblocks-cms-docs/docs/ai-page-building-guide.mdwebblocks-cms-docs/docs/internal-content-api.mdwebblocks-cms-docs/docs/api-discovery.mdwebblocks-cms-docs/docs/block-type-contracts.mdwebblocks-cms-docs/docs/public-block-render-markup.mdwebblocks-cms-docs/docs/block-ui-renderer-contract.mdwebblocks-cms-docs/docs/public-theme-and-tones.mdwebblocks-cms-docs/docs/public-assets.mdwebblocks-cms-docs/docs/media-image-variants.md
This inventory should be the first document an AI reads for page-design capability selection. The detailed references remain useful for endpoint workflows, historical compatibility, and full renderer notes.
Plugin startup and recovery contract
Catalog and ZIP installation, updates, and panel/API activation validate plugin source,
provider startup, commands, and routes in a fresh PHP process through cms:plugin-probe.
Validation is required even when no migration is pending. A failed or timed-out probe
leaves the current package active; subprocess diagnostics are not exposed in responses.
The default startup timeout is 30 seconds (webblocks-plugins.install.boot_timeout_seconds).
Successful updates retain the previous package and record whether migrations ran.
Database setup failures leave the plugin disabled and preserve its tables and packages.
Runtime source/route failures quarantine the plugin; an explicit disable overrides
configuration-based enablement. Lifecycle JSON records use atomic replacement.
/webadmin/plugin-recovery and its login form load without installed plugin source,
routes, or commands. Existing CMS login controls, active admin-access and Super admin authorization, and CSRF
protection apply. Recovery can disable a plugin or restore the retained package when
no migration ran, after another startup probe. A restore also republishes its assets.
This is recovery for CMS-managed packages; it does not isolate arbitrary host providers
or sandbox executable PHP. Uncatchable process termination still requires the separate
recovery request rather than an in-process error handler.