
- MODX 3
- PHP 8.2
- Vue 3


You build the field set in the inspector (text, email, phone, textarea, select, radio, checkbox, date), set Form key and success text. Submission goes through FetchIt and the PageBuilderContactForm snippet. Do not call the handler from the template.

Информация
Requires PageBuilder Pro and FetchIt.
form_key (pb_form_key)published_jsonForm key (form_key) must be unique on the page if you have several forms. Repeater Form fields: name, label, type (text, email, phone, textarea, select, radio, checkbox, date), required. For select and radio, write options one per line (Label|value or value only). Field name: [a-z][a-z0-9_]*. A required checkbox stays empty until the value is 1, yes, true, or on.
Email recipient: emailsender or site mail settings (same as handler). Without FetchIt the section shows a form unavailability message.
| Parameter | Value |
|---|---|
| key | contact_form |
| Layer | Pro |
| Category | conversion (conversion) |
| Chunk | pagebuilderpro_contact_form |
| Requirements | pro, FetchIt |
Fill fields in the section inspector on the resource. Field type descriptions: type reference.
title) Type text. Optional.
intro) Type textarea. Optional.
form_key) Type text. Required.
fields) Type repeater. Required. Repeating rows. Add button in inspector.
Each row:
| Field | Type | Label | Required |
|---|---|---|---|
name | text | Field name (name) | yes |
label | text | Label | yes |
type | select | Field type | yes |
required | yesno | Required | no |
submit_label) Type text. Optional.
success_message) Type textarea. Optional.
redirect_url) Type url. Optional.
Section pb-contact-form. AJAX via FetchIt → PageBuilderContactForm. Honeypot nospam: silent success without email.
Example JSON after section save (field schema, not visitor responses):
{
"title": "Leave a request",
"intro": "We will reply during business hours.",
"form_key": "contact",
"fields": [
{
"_rowId": "00000000-0000-4000-8000-000000000001",
"name": "name",
"label": "Name",
"type": "text",
"required": true
},
{
"_rowId": "00000000-0000-4000-8000-000000000002",
"name": "email",
"label": "Email",
"type": "email",
"required": true
}
],
"submit_label": "Send",
"success_message": "Thank you! We will contact you soon.",
"redirect_url": "https://example.com/thanks"
}Fenom chunk pagebuilderpro_contact_form:
{set $formKey = $form_key|default:'contact'}
<section class="pb-section pb-section--contact-form pb-contact-form{if $cssClass} {$cssClass|escape}{/if}" data-pb-section="contact_form"{if $id} id="pb-{$id|escape}"{/if}>
<div class="pb-section__inner pb-contact-form__inner">
{if $title}
<h2 class="pb-heading pb-contact-form__title">{$title|escape}</h2>
{/if}
{if $intro}
<p class="pb-contact-form__intro">{$intro|escape}</p>
{/if}
{if !$fetchit_available}
<p class="pb-contact-form__fallback" role="status">{$lex_form_unavailable|escape}</p>
{else}
{'!PageBuilderFetchIt' | snippet : [
'snippet' => 'PageBuilderContactForm',
'form' => 'pagebuilderpro_contact_form_fields',
'form_key' => $formKey,
'resource_id' => $resource_id|default:0,
'successMessage' => ($success_message ?: $lex_success_default),
'validationErrorMessage' => $lex_validation_error,
'clearFieldsOnSuccess' => 1,
'fields' => $fields,
'form_csrf' => $form_csrf,
'submit_label' => $submit_label,
'lex_submit' => $lex_submit,
'lex_field_required' => $lex_field_required,
'lex_field_email' => $lex_field_email,
'cssClass' => $cssClass,
'id' => $id,
]}
{/if}
</div>
</section>Fenom chunk pagebuilderpro_contact_form_fields:
{set $formKey = $form_key|default:'contact'}
{set $submitText = $submit_label|default:$lex_submit}
<form class="pb-contact-form__form fetchit-form" method="post" novalidate>
<input type="hidden" name="pb_form_key" value="{$formKey|escape}" />
<input type="hidden" name="pb_csrf" value="{$form_csrf|escape}" />
<input type="hidden" name="nospam" value="" tabindex="-1" autocomplete="off" aria-hidden="true" class="pb-contact-form__honeypot" />
<div class="pb-contact-form__message pb-contact-form__message--success" data-success role="status"></div>
<div class="pb-contact-form__message pb-contact-form__message--error" data-validation-error role="alert"></div>
<div class="pb-contact-form__fields">
{foreach $fields as $field}
{set $fname = $field.name|default:''}
{if $fname == ''}{continue}{/if}
{set $flabel = $field.label|default:$fname}
{set $ftype = $field.type|default:'text'}
{set $frequired = $field.required|default:0}
{set $options = $field.options_list|default:($field.options|default:[])}
{set $fid = "pb-{$formKey|escape}-{$fname|escape}"}
<div class="pb-contact-form__field" data-custom="{$fname|escape}">
{if $ftype == 'checkbox'}
<label class="pb-contact-form__check" for="{$fid}">
<input type="checkbox" id="{$fid}" name="{$fname|escape}" value="1" {if $frequired}required aria-required="true"{/if} />
<span>{$flabel|escape}{if $frequired}<span class="pb-contact-form__required" aria-hidden="true">*</span>{/if}</span>
</label>
{elseif $ftype == 'textarea'}
<label class="pb-contact-form__label" for="{$fid}">
{$flabel|escape}{if $frequired}<span class="pb-contact-form__required" aria-hidden="true">*</span>{/if}
</label>
<textarea class="pb-contact-form__control" id="{$fid}" name="{$fname|escape}" rows="4" {if $frequired}required aria-required="true"{/if}></textarea>
{elseif $ftype == 'select'}
<label class="pb-contact-form__label" for="{$fid}">
{$flabel|escape}{if $frequired}<span class="pb-contact-form__required" aria-hidden="true">*</span>{/if}
</label>
<select class="pb-contact-form__control" id="{$fid}" name="{$fname|escape}" {if $frequired}required aria-required="true"{/if}>
<option value="">—</option>
{foreach $options as $option}
{set $ovalue = $option.value|default:$option}
{set $olabel = $option.label|default:$ovalue}
<option value="{$ovalue|escape}">{$olabel|escape}</option>
{/foreach}
</select>
{elseif $ftype == 'radio'}
<fieldset class="pb-contact-form__fieldset">
<legend>{$flabel|escape}{if $frequired}<span class="pb-contact-form__required" aria-hidden="true">*</span>{/if}</legend>
{foreach $options as $option}
{set $ovalue = $option.value|default:$option}
{set $olabel = $option.label|default:$ovalue}
<label class="pb-contact-form__check">
<input type="radio" name="{$fname|escape}" value="{$ovalue|escape}" {if $frequired}required aria-required="true"{/if} />
<span>{$olabel|escape}</span>
</label>
{/foreach}
</fieldset>
{else}
<label class="pb-contact-form__label" for="{$fid}">
{$flabel|escape}{if $frequired}<span class="pb-contact-form__required" aria-hidden="true">*</span>{/if}
</label>
<input
class="pb-contact-form__control"
id="{$fid}"
type="{if $ftype == 'email'}email{elseif $ftype == 'phone'}tel{elseif $ftype == 'date'}date{else}text{/if}"
name="{$fname|escape}"
{if $ftype == 'email'}autocomplete="email"{elseif $ftype == 'phone'}autocomplete="tel" inputmode="tel"{elseif $fname == 'name'}autocomplete="name"{/if}
{if $frequired}required aria-required="true"{/if}
/>
{/if}
<span class="pb-contact-form__error" data-error="{$fname|escape}"></span>
</div>
{/foreach}
</div>
<button class="pb-button pb-contact-form__submit" type="submit">{$submitText|escape}</button>
</form>Without FetchIt the chunk prints lexicon pagebuilder_fe_form_unavailable.