Skip to main content

Formatting Examples & Recipes

These examples assume a form or field object is already available. Replace field handles, classes, and paths with your own. See Template Overrides for the complete reference.

Use the Template Code and Output tabs to compare each change. Output examples show the relevant markup; Freeform's additional IDs, hidden inputs, ARIA attributes, and other generated attributes are omitted where they do not help explain the override. Exact markup depends on your formatting template and field settings.

​On Form tag and Rows

Set attributes on the form and row wrappers.

{{ form.render({
attributes: {
novalidate: true,
"data-my-form": true,
class: "my-form-class",
row: {
class: "row",
"data-row": true,
},
}
}) }}

​On All Fields

Use @global for shared attributes, then add more specific selectors.

{{ form.render({
attributes: {
novalidate: true,
row: {
class: "row",
},
},
fields: {
"@global": {
attributes: {
input: {
class: "input-class",
},
container: {
"data-container": true,
},
label: {
class: "label-class",
},
},
},
"@dropdown": {
attributes: {
input: {
class: "select fullwidth",
},
container: {
"data-select-container": true,
},
},
},
"@checkboxes, @multiple-select": {
instructions: "Select all that apply.",
},
"myFieldHandle": {
label: "My Field Label Override",
instructions: "My field instructions override.",
value: "my field value override",
attributes: {
container: {
"data-my-input-container": true,
},
input: {
class: "big-text",
},
},
},
},
}) }}

​On Field Containers

Add attributes to a field wrapper. See Overriding HTML Tags for accessible choice-group markup.

{{ field.render({
attributes: {
container: {
tag: "div",
class: "certain-class",
"data-container": true,
},
},
}) }}

​On All Parts of the Fields

Override a field's label, instructions, initial value, and attribute locations together.

{{ field.render({
label: "My Field Label Override",
instructions: "My field instructions override.",
value: "my field value override",
attributes: {
container: {
class: "container",
},
input: {
"data-field": true,
class: "input-element",
},
label: {
class: "label",
},
instructions: {
class: "instructions",
},
error: {
class: "error-block",
},
}
}) }}

​On Submit Buttons

Set button wrapper attributes and labels. For placement or custom markup, see Submit Button Customization.

{{ form.render({
buttons: {
attributes: {
container: {
style: "border: 1px solid red;",
},
column: {
style: "background: #ccc;",
},
buttonWrapper: {
style: "padding: 0 5px;",
},
submit: {
class: "btn btn-primary",
},
back: {
class: "btn btn-secondary",
},
save: {
class: "btn btn-secondary",
}
},
submitLabel: "Send",
backLabel: "Previous",
saveLabel: "Save",
},
}) }}

​On Captcha Wrapper

Add attributes to automatically inserted captcha wrappers. For placement, see Captcha Placement.

{{ form.render({
captchas: {
class: ["custom-class", "another-class"],
"data-test": true,
}
}) }}

​Override Field Values

Prepopulate text fields or select configured option values. These are initial values, not a way to enforce trusted submitted data. Set these before rendering your fields, and keep renderTag() paired with renderClosingTag() in the complete template. See Passing Dynamic Data to Forms for more patterns.

{% set entry = craft.entries.slug(craft.app.request.getSegment(2)).one() %}

{{ form.renderTag({
fields: {
"entryTitle": {
value: entry ? entry.title : ''
},
"stateSelect": {
value: "AZ"
},
"availability": {
value: ["tue", "thu"]
},
"firstName": {
value: currentUser ? currentUser.name : ''
},
}
}) }}

​Array Values & Conditionals

Use arrays to assemble classes or other attribute values. Empty, false, or null array entries are omitted.

{{ field.render({
attributes: {
label: {
id: "label-for-" ~ field.handle,
class: [
"form-control-label",
field.hasErrors ? "is-invalid has-validation",
field.required ? "required",
field.type == "checkbox" ? "checkbox" : "non-checkbox",
],
},
},
}) }}

​Boolean Values

A standalone attribute is rendered for true or null; false omits it.

{{ field.render({
attributes: {
label: {
"data-required": false,
"data-is-blue": true,
"data-is-some-data": null,
}
}
}) }}

​Populate Freeform Field Data

For dynamic option sources, first check Populating Field Options. When custom template code is necessary, follow Populate Field Options at Template Level. The code below belongs inside a field-rendering loop and assumes a Text field configured with the handle myFieldHandle.

{% if field.handle == 'myFieldHandle' %}
{{ field.renderLabel() }}
<select name="{{ field.handle }}" id="{{ field.idAttribute }}">
{% for entry in craft.entries.section('news').limit(10).all() %}
<option value="{{ entry.id }}"{% if field.value == entry.id %} selected{% endif %}>
{{ entry.title }}
</option>
{% endfor %}
</select>
{{ field.renderErrors() }}
{% else %}
{{ field.render() }}
{% endif %}

For complete row-and-field rendering patterns, see Rendering Forms Manually.