Grid
The Grid formatting template implementation includes a lot more CSS to style it correctly. You can place the CSS and JS inside the formatting template or add to your site's CSS / JS files.
Preview
Video: Preview of Formatting Template Examples
Formatting
{# Opening <form> tag #}
{{ form.renderTag }}
{# Display page tabs if Multi-page form #}
{% if form.pages|length > 1 %}
<ul class="freeform-pages">
{% for page in form.pages %}
<li>
{% if form.currentPage.index == page.index %}
<b>{{ page.label }}</b>
{% else %}
{{ page.label }}
{% endif %}
</li>
{% endfor %}
</ul>
{% endif %}
{# Display Error banner and general errors if applicable #}
{% if form.hasErrors %}
<div class="freeform-form-has-errors">
{{ "Error! Please review the form and try submitting again."|t('freeform') }}
{% if form.errors|length %}
<ul>
{% for error in form.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
</div>
{% endif %}
{# Render form fields #}
{% for row in form %}
<div class="freeform-row {{ form.customAttributes.rowClass }}">
{% for field in row %}
{% set columnClass = "freeform-column " ~ form.customAttributes.columnClass %}
{% set columnClass = columnClass ~ " freeform-column-" ~ (12 / (row|length)) %}
{% if field.type == "submit" %}
{% set columnClass = columnClass ~ " freeform-column-content-align-" ~ field.position %}
{% endif %}
<div class="{{ columnClass }}"{{ field.rulesHtmlData }}>
{{ field.render({
class: field.type not in ["submit", "signature"] ? "freeform-input" : "",
labelClass: "freeform-label" ~ (field.inputOnly ? " freeform-input-only-label" : "") ~ (field.required ? " freeform-required" : ""),
errorClass: "freeform-errors",
}) }}
{# FOR FREEFORM PAYMENTS #}
{% if field.layoutRows is defined %}
{% for layoutRow in field.layoutRows %}
<div class="freeform-row {{ form.customAttributes.rowClass }}">
{% set layoutWidth = (12 / (layoutRow|length)) %}
{% set columnClass = columnClass|replace(' col-lg-' ~ (row|length)) %}
{% set columnClass = columnClass ~ " col-lg-" ~ layoutWidth %}
{% for layoutField in layoutRow %}
<div class="{{ columnClass }}">
{{ layoutField.render({
class: "freeform-input",
labelClass: "freeform-label" ~ (layoutField.inputOnly ? " freeform-input-only-label" : "") ~ (layoutField.required ? " freeform-required" : ""),
errorClass: "freeform-errors",
}) }}
</div>
{% endfor %}
</div>
{% endfor %}
{% endif %}
</div>
{% endfor %}
</div>
{% endfor %}
{# Closing </form> tag #}
{{ form.renderClosingTag }}
CSS
The following CSS is a supplemental starting point to get forms appearing robustly.
button[type='submit'].ff-loading {
display: inline-flex;
flex-wrap: nowrap;
align-items: center;
}
button[type='submit'].ff-loading:before {
content: '';
display: block;
flex: 1 0 11px;
width: 11px;
height: 11px;
margin-right: 10px;
border-style: solid;
border-width: 2px;
border-color: transparent transparent #fff #fff;
border-radius: 50%;
animation: ff-loading 0.5s linear infinite;
}
@keyframes ff-loading {
0% {
transform: rotate(0);
}
100% {
transform: rotate(1turn);
}
}
.freeform-pages {
padding: 0;
margin: 0 0 10px;
list-style: none;
}
.freeform-pages:after {
content: '';
display: table;
clear: both;
}
.freeform-pages li {
float: left;
margin: 0 10px 0 0;
}
.freeform-row {
display: block;
margin: 0 -15px;
}
.freeform-row:after {
content: '';
display: table;
clear: both;
}
.freeform-row .freeform-column {
display: block;
padding: 10px 15px;
float: left;
box-sizing: border-box;
}
.freeform-row .freeform-column:after {
content: '';
display: table;
clear: both;
}
.freeform-row .freeform-column > .freeform-row:first-child {
margin-top: -10px;
}
.freeform-row .freeform-column label {
display: block;
}
.freeform-row .freeform-column .input-group-one-line label {
display: inline-block;
padding-right: 10px;
}
.freeform-row .freeform-column .freeform-label {
font-weight: bold;
}
.freeform-row .freeform-column .freeform-label.freeform-required:after {
content: '*';
margin-left: 5px;
color: red;
}
.freeform-row .freeform-column .freeform-input {
width: 100%;
display: block;
box-sizing: border-box;
}
.freeform-row .freeform-column .freeform-input[type='checkbox'],
.freeform-row .freeform-column .freeform-input[type='radio'] {
width: auto;
display: inline;
margin-right: 5px;
}
.freeform-row .freeform-column .freeform-input.StripeElement {
padding: 4px 2px;
border: 1px solid #ccc;
height: 30px;
}
.freeform-row .freeform-column .freeform-input-only-label {
font-weight: normal;
}
.freeform-row .freeform-column .freeform-input-only-label > .freeform-input {
display: inline-block;
width: auto;
margin-right: 5px;
}
.freeform-row .freeform-column .freeform-errors,
.freeform-row .freeform-column .ff-errors {
list-style: none;
padding: 0;
margin: 5px 0 0;
}
.freeform-row .freeform-column .freeform-errors > li,
.freeform-row .freeform-column .ff-errors > li {
color: red;
}
.freeform-row .freeform-column .freeform-instructions {
margin: 0 0 5px;
font-size: 13px;
color: #aba7a7;
}
.freeform-row .freeform-column.freeform-column-content-align-left {
text-align: left;
}
.freeform-row
.freeform-column.freeform-column-content-align-left
button:not(:first-of-type) {
margin-left: 5px;
}
.freeform-row .freeform-column.freeform-column-content-align-center {
text-align: center;
}
.freeform-row
.freeform-column.freeform-column-content-align-center
button:not(:first-of-type) {
margin-left: 5px;
}
.freeform-row .freeform-column.freeform-column-content-align-right {
text-align: right;
}
.freeform-row
.freeform-column.freeform-column-content-align-right
button:not(:first-of-type) {
margin-left: 5px;
}
.freeform-row
.freeform-column.freeform-column-content-align-spread
button:first-child {
float: left;
}
.freeform-row
.freeform-column.freeform-column-content-align-spread
button:last-child {
float: right;
}
.freeform-row .freeform-column-1 {
width: 8.3333333333%;
}
.freeform-row .freeform-column-2 {
width: 16.6666666667%;
}
.freeform-row .freeform-column-3 {
width: 25%;
}
.freeform-row .freeform-column-4 {
width: 33.3333333333%;
}
.freeform-row .freeform-column-5 {
width: 41.6666666667%;
}
.freeform-row .freeform-column-6 {
width: 50%;
}
.freeform-row .freeform-column-7 {
width: 58.3333333333%;
}
.freeform-row .freeform-column-8 {
width: 66.6666666667%;
}
.freeform-row .freeform-column-9 {
width: 75%;
}
.freeform-row .freeform-column-10 {
width: 83.3333333333%;
}
.freeform-row .freeform-column-11 {
width: 91.6666666667%;
}
.freeform-row .freeform-column-12 {
width: 100%;
}
.ff-form-errors {
padding: 15px;
border: 1px solid #f5c6cb;
background: #f8d7da;
border-radius: 5px;
color: #721c24;
}
.ff-form-errors > p {
margin: 0;
}
.freeform-form-has-errors {
color: red;
}
JS
The following JS is a supplemental starting point to handle additional elements in the form.
// Styling for Stripe Payments field
document.addEventListener('freeform-stripe-styling', function (event) {
event.detail.base = {
fontSize: '16px',
fontFamily:
'-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"',
};
});
Live Demo
The demo below is a live demo site that shows most of what the Demo Templates include (some sections and data has been limited).