Declarative fields

Declarative HTML fields

Library sections and hand-authored Tailwind blocks can expose right-column Content controls without PHP and without a custom JS plugin. You mark editable parts of the HTML with data-* attributes (markers). VoodBuilder’s editor discovers them, builds the Content / Layout items UI, and writes values back into the canvas. Save/load is the page HTML — there is no separate config document for these fields.

This is different from companion dynamic blocks (pricing, model-bound content, remote APIs), which keep their own config + server render path. Leave those alone; declarative markers are for static Tailwind HTML.

Practical walkthrough: Building sections & sidebar settings.

What is a marker?

A marker is a normal HTML attribute that VoodBuilder recognises. Example:

HTML
<h2
  data-vb-field="heading"
  data-vb-field-type="text"
  data-vb-field-label="Heading"
>
  Hello
</h2>
  • data-vb-field — this node is an editable field (required key)
  • data-vb-field-type — control type in the inspector
  • data-vb-field-label — label shown in the Content panel

No extra PHP or per-block JS is required for the cases below: core already interprets these markers.

Content fields (data-vb-field)

Attribute Purpose
data-vb-field Field key (required), e.g. heading, title
data-vb-field-type See types below (default text)
data-vb-field-label Label in the Content panel (optional; otherwise the key is humanised)

Supported types

Type Aliases Behaviour
text — Single-line text
textarea — Multi-line text
number — Numeric input (writes into the element’s text content)
icon — Icon picker (use with an icon host; see below)
rich richeditor, html Rich text host (data-voodbuilder-rich-text / .vb-rich-text)
status check, boolean, yesno Yes / no toggle via data-vb-status="yes|no"

Icons and rich hosts auto-detect when the node is (or contains) the appropriate host element.

Icons

HTML
<span
  data-voodbuilder-icon
  data-vb-icon="star"
  data-vb-icon-size="size-5"
  data-vb-icon-style="outline"
  data-vb-icon-stroke="1.75"
  data-vb-field="icon"
  data-vb-field-type="icon"
  data-vb-field-label="Icon"
></span>

Rich text

HTML
<div
  class="vb-rich-text"
  data-voodbuilder-rich-text
  data-vb-field="body"
  data-vb-field-type="rich"
  data-vb-field-label="Body"
>
  <p>Body copy</p>
</div>

Status (yes / no)

HTML
<div
  data-vb-field="highlighted"
  data-vb-field-type="status"
  data-vb-field-label="Highlighted"
  data-vb-status="yes"
>
  …
</div>

The inspector shows a ✓ / ✕ control — not a rich editor.

Repeating items (grids, cards, feature rows)

For sections with a variable number of cards/items:

Attribute Where Purpose
data-vb-item-count Section root Enables Layout items (current count)
data-vb-item-min / data-vb-item-max Section root Allowed range (defaults roughly 1–8)
data-vb-item-columns Section root Column count (1–6) for the items grid
data-vb-items-root Items container Parent of repeating children
data-vb-item Each repeatable child One card / cell
data-vb-items-layout="preserve" Section and/or items root Clone/remove items without rewriting author grid/card Tailwind classes

When the section is selected, the inspector shows Number of items and Columns. Select a card on the canvas to edit that item’s data-vb-field values. Nested items (e.g. FAQ categories containing questions) are supported when each level uses the items markers correctly.

Optional fragments

Attribute Purpose
data-vb-optional Any key — Content checkbox to show/hide an optional fragment
data-vb-optional-label Label for that checkbox

Tables

Table markup can expose row/column controls from structure:

Marker Purpose
data-vb-table Table root recognised by the inspector
data-vb-table-col Column metadata for header/cells

Catalog HTML that uses tables should keep table nodes on the default component type so the inspector can manage rows/columns reliably.

Minimal example

HTML
<section
  class="bg-vp-bg px-5 py-24 text-vp-text-2"
  data-voodbuilder-section-block="my-features"
  data-vb-item-count="3"
  data-vb-item-min="1"
  data-vb-item-max="8"
  data-vb-item-columns="3"
  data-vb-items-layout="preserve"
>
  <div class="mx-auto max-w-5xl">
    <h2
      class="font-serif text-3xl font-bold text-vp-text-1"
      data-vb-field="heading"
      data-vb-field-type="text"
      data-vb-field-label="Heading"
    >
      Features
    </h2>

    <div
      class="mt-10 grid gap-6 md:grid-cols-3"
      data-vb-items-root
      data-vb-items-layout="preserve"
    >
      <div class="rounded-xl border border-vp-border p-6" data-vb-item>
        <span
          class="inline-flex text-vp-brand-1"
          data-voodbuilder-icon
          data-vb-icon="star"
          data-vb-field="icon"
          data-vb-field-type="icon"
          data-vb-field-label="Icon"
        ></span>
        <h4
          class="mt-3 font-bold text-vp-text-1"
          data-vb-field="title"
          data-vb-field-type="text"
          data-vb-field-label="Title"
        >
          Card title
        </h4>
        <p
          class="mt-2 text-vp-text-2"
          data-vb-field="text"
          data-vb-field-type="textarea"
          data-vb-field-label="Text"
        >
          Short description.
        </p>
      </div>
    </div>
  </div>
</section>

Tips:

  • Keep one template item inside data-vb-items-root; the editor clones it when the item count increases.
  • Prefer data-vb-items-layout="preserve" for hand-tuned Tailwind grids.
  • Prefer theme tokens (vp-*) so Theme Studio light/dark stays consistent — see Theme Studio.

Style (background, colour, spacing)

Background colour, typography, padding, borders, and similar visuals belong in the Style inspector (Tailwind classes), not in data-vb-field. Declarative fields are for content and item layout (count / columns), not for every visual token.

Persistence

Concern How it is stored
Field values Text / attributes / icon attrs on the canvas nodes
Item count & columns Attributes on the section (data-vb-item-count, data-vb-item-columns, …)
Visual style CSS classes / Style panel on the same HTML

Saving the page persists the HTML. Reloading the editor rehydrates Content and Layout items from those markers.

What this is not

Need Use instead
Live Eloquent / collections Dynamic Data
HTTP / remote lists Dynamic API
Server-rendered companion blocks Companion packages with their own settings + render path
Pagination of many items at runtime Front-end behaviour or a dynamic/server block — not a declarative marker alone
Custom inspector controls beyond built-in field types Editor JS (registerBlockSettings) or extend core field types

Remote catalog tiles from Elements can (and should) use the same markers in their HTML so authors get Content / Layout items out of the box. Agency Components saved from marked HTML keep those fields when re-inserted.