Form object
The Form object contains its metadata and field objects. You can either render the form using the pre-selected formatting template by calling form.render() or achieve a more fine-grained control over it by iterating over its rows and fields and using form.renderTag and form.renderClosingTag methods.
Freeform will automatically insert javascript in the footer of the page for features such as Spam Protection, Submit disable on click, and other special fieldtypes. If you prefer to have this load inside the <form></form> tags, you can adjust the Script Insert Location Location setting.
User Guides
- Using headless website architecture with JavaScript-based front-end frameworks such as Vue.js, Next.js, React JS and more.
- Quick troubleshooting the most commonly reported issues with your form's appearance, behavior, or submission of the form on the front end.
- Using a form more than once in the same template? Check out the additional steps necessary to prevent potential issues.
Properties
name
Outputs the name of the form.
handle
Outputs the handle of the form.
id
Outputs the unique ID of the form.
description
Outputs the description of the form.
submissionTitleFormat
Outputs the submission title format used when creating new submissions based on this form.
returnUrl
Outputs the return URL of the form.
successMessage
Outputs the custom success message configured in the Validation tab for your form inside the form builder.
errorMessage
Outputs the custom error message configured in the Validation tab for your form inside the form builder.
hasErrors
A bool variable, which will be true if there are any errors in any of the fields or the form. It might be true even if form.errors list is empty, (e.g. if one or more fields have an error). This can be used in conjunction with the Errors object for displaying special and general errors.
pages
Returns a list of Page objects each containing its label and index.
currentPage
Returns the current Page object containing its label and index.
duplicateRenamed and Revised in 5.0+
A bool variable, which will be true if the form has the Duplicate Check setting enabled (duplicate submission check) and the user has already submitted the form.
stopSubmissionsAfterNew in 5.11.8+
Returns the date specified in the Stop Submissions After Date setting for the form. Can be used as a conditional to hide the form and/or show a message to the user if the form has passed its close date.
{% if form.stopSubmissionsAfter|date >= now|date %}
<p>The deadline to submit this form was {{ form.stopSubmissionsAfter|date }}.</p>
{% endif %}
isIntegrationEnabledNew in 5.6+
Allows you to check if an integration is enabled for a form. Use the integration handle you created for each integration.
For Singles, the handles are:
- Honeypot:
honeypot - Javascript Test:
javascript-test - Google Tag Manager:
gtm - Post Forwarding:
post-forwarding
<ul>
{% if form.isIntegrationEnabled("mailchimp") %}
<li>Mailchimp is enabled</li>
{% endif %}
{% if form.isIntegrationEnabled("honeypot") %}
<li>Honeypot is enabled</li>
{% endif %}
{% if form.isIntegrationEnabled("recaptchaV3") %}
<li>reCAPTCHA v3 is enabled</li>
{% endif %}
</ul>
Template OverridesNew in 5.0+
Template overrides let you customize form and field attributes, values, and rendering. All overrides are optional.
| Option | Purpose |
|---|---|
attributes | Controls form-tag, row, and banner attributes. |
buttons | Controls Submit button output. |
fields | Controls field values, attributes, and rendering. |
captchas | Adds attributes to the CAPTCHA wrapper automatically inserted by Freeform. |
tag | Changes supported HTML tags. Learn more.New in 5.10+ |
See Template Overrides for syntax and examples.
In Freeform 5.17+, the default AJAX renderer also uses banner attributes and field-error styling from compatible formatting templates. JavaScript overrides remain available for additional customization. See AJAX Forms for details.
Need to pass a custom value to your formatting template, such as whether to display the form title? See Passing a Custom Property to a Formatting Template.
Usage in Templates
Simple Render
A basic implementation might look like this:
{% set form = freeform.form("myFormHandle") %}
{{ form.render() }}
Override Classes & Values
Once Template Overrides have been implemented, your code might look something like this:
{% set form = freeform.form("myFormHandle") %}
{{ form.render({
attributes: {
novalidate: true,
class: "my-form-class",
},
buttons: {
attributes: {
submit: { class: "form-field-button blue" },
back: { class: "form-field-button gray" },
},
},
fields: {
"@global": {
attributes: {
input: {
class: "form-field-input",
},
label: {
class: "form-field-label",
},
},
},
":required": {
attributes: {
label: { "+class": "form-field-required" },
},
},
":errors": {
attributes: {
input: { "+class": "form-field-is-invalid" },
},
},
"@dropdown": {
attributes: {
container: {
"data-select-container": true,
},
input: {
"+class": "form-field-select fullwidth",
},
},
},
"@checkboxes, @radios" : {
attributes: {
input: {
"+class": "form-field-options",
},
},
},
"myFieldHandle": {
value: entry.id,
},
},
}) }}
Manually Iterate
Manually iterate through form fields inside your regular template:
{# Set the form #}
{% set form = freeform.form("myFormHandle") %}
{# Render the opening form tag #}
{{ form.renderTag({
attributes: {
row: { class: "freeform-row" },
success: { class: "freeform-form-success" },
errors: { class: "freeform-form-errors" },
novalidate: true,
},
buttons: {
attributes: {
container: { class: "freeform-button-container" },
column: { class: "freeform-button-column" },
buttonWrapper: { class: "freeform-button-wrapper" },
submit: { class: "freeform-button-submit" },
back: { class: "freeform-button-back" },
save: { class: "freeform-button-save" },
},
},
fields: {
"@global": {
attributes: {
container: { class: "freeform-column" },
input: {
"data-field": true,
class: "freeform-input",
},
label: { class: "freeform-label" },
instructions: { class: "freeform-instructions" },
error: { class: "freeform-errors" },
},
},
":required": {
attributes: {
label: { "+class": "freeform-required" },
},
},
":errors": {
attributes: {
input: { "+class": "is-invalid has-validation" },
},
},
"@group": {
attributes: {
label: { "+class": "group-label" },
},
},
"@signature": {
attributes: {
input: { "-class": "freeform-input" },
},
}
},
}) }}
{# Success and error message handling for non-AJAX forms #}
{% if not form.settings.ajax %}
{% if form.submittedSuccessfully %}
<div{{ form.attributes.success|raw }}>
<p>{{ form.successMessage | t('freeform') }}</p>
</div>
{% endif %}
{% if form.hasErrors %}
<div{{ form.attributes.errors|raw }}>
<p>{{ form.errorMessage | t('freeform') }}</p>
{% if form.errors|length %}
<ul>
{% for error in form.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
</div>
{% endif %}
{% endif %}
{# Render page tabs if multi-page #}
{% if form.pages|length > 1 %}
<ul class="freeform-pages">
{% for page in form.pages %}
<li {% if form.currentPage.index == page.index %}class="active"{% endif %}>
{% if form.currentPage.index == page.index %}
<b>{{ page.label }}</b>
{% else %}
{{ page.label }}
{% endif %}
</li>
{% endfor %}
</ul>
{% endif %}
{# Build form rows and fields #}
{% macro renderRows(form, rows) %}
{% for row in rows %}
{% set width = (12 / (row|length)) %}
<div{{ form.attributes.row|raw }}>
{% for field in row %}
{% do field.setParameters({
attributes: {
container: { class: [
"freeform-column-" ~ width,
"freeform-fieldtype-" ~ field.type,
]},
},
}) %}
{% if field.type == "group" %}
<div class="freeform-group">
<label{{ field.attributes.label }}>
{{ field.label }}
</label>
<div>
{{ _self.renderRows(form, field.layout) }}
</div>
</div>
{% else %}
{{ field.render }}
{% endif %}
{% endfor %}
</div>
{% endfor %}
{% endmacro %}
{# Display form field rows and columns #}
{{ _self.renderRows(form, form.rows) }}
{# Render the closing form tag #}
{{ form.renderClosingTag }}
Success Flash
When not using AJAX, the session success flash message (displays only once) when the form is successfully submitted:
{% set form = freeform.form("myForm") %}
{% if form.submittedSuccessfully %}
<div>You've successfully submitted this form!</div>
{% endif %}
{{ form.render }}
Error when Duplicate
Display a message when the submission is a duplicate:
{% set form = freeform.form("myForm") %}
{% if form.duplicate %}
<div class="alert alert-warning duplicate">
You've already submitted this form!
</div>
{% else %}
{{ form.render }}
{% endif %}