FlexboxImproved in 5.0+
The Flexbox 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
Templates
- flexbox.twig
{# CSS styling #}
<style>
button[type=submit].freeform-processing {
display: inline-flex;
flex-wrap: nowrap;
align-items: center;
}
button[type=submit].freeform-processing: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: freeform-processing .5s linear infinite;
}
@keyframes freeform-processing {
0% {
transform: rotate(0);
}
100% {
transform: rotate(1turn);
}
}
.freeform-pages {
display: flex;
padding: 0;
margin: 0 0 10px;
list-style: none;
}
.freeform-pages li {
margin: 0 10px 0 0;
}
.freeform-row {
display: flex;
justify-content: space-between;
margin: 0 -15px;
}
.freeform-row .freeform-column {
flex: 1 0;
padding: 10px 0;
margin: 0 15px;
box-sizing: border-box;
}
.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 {
display: flex;
flex-wrap: wrap;
}
.freeform-row .freeform-column .input-group-one-line label {
padding-right: 10px;
}
.freeform-row .freeform-column .freeform-label,
.freeform-group .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-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 {
list-style: none;
padding: 0;
margin: 5px 0 0;
}
.freeform-row .freeform-column .freeform-errors > li {
color: red;
}
.freeform-row .freeform-column .freeform-instructions {
margin: 0 0 5px;
font-size: 13px;
color: #aba7a7;
}
.freeform-form-errors {
padding: 15px;
border: 1px solid #f5c6cb;
background: #f8d7da;
border-radius: 5px;
color: #721c24;
}
.freeform-form-errors > p {
margin: 0;
}
.freeform-group {
width: 100%;
padding: 0 15px;
}
</style>
{# Render the opening form tag #}
{{ form.renderTag({
attributes: {
row: { class: "freeform-row" },
success: { class: "freeform-form-success" },
errors: { class: "freeform-form-errors" },
},
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: {
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" },
},
}
},
}) }}
{# JS overrides #}
<script>
var form = document.querySelector('[data-id="{{ form.anchor }}"]');
if (form) {
form.addEventListener("freeform-stripe-appearance", function (event) {
event.elementOptions.appearance = Object.assign(
event.elementOptions.appearance,
{
variables: {
colorPrimary: "#0d6efd",
},
}
);
});
}
</script>
{# Success and error message handling for non-AJAX forms #}
{% if not form.settings.ajax %}
{% if form.submittedSuccessfully %}
<div{{ form.attributes.success|raw }}>
<p>{{ form.settings.successMessage | t('freeform') }}</p>
</div>
{% endif %}
{% if form.hasErrors %}
<div{{ form.attributes.errors|raw }}>
<p>{{ form.settings.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 }}
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).