Validation is based on Parsley.js
formValidator.data-parsley-trigger attribute.input, as they would otherwise display an error immediately upon entry.data-parsley-file-types attribute. The value must be a comma-separated list of file types (e.g. image/jpeg, image/png).data-parsley-max-file-size attribute. The value must be specified in kilobytes without a unit (e.g. 1024).Internet Explorer
There are problems with input fields of type “Date” in Internet Explorer (all versions) and Parsley.js, as Internet Explorer ignores the local format. The value of the field in IE always has the pattern “YYYY-MM-DD”, but Parsley expects, for example, “DD.MM.YYYY” in German and marks the field as erroneous.
This incompatibility is solved via a script that converts all fields of type “Date” to fields of type “Text” in Internet Explorer and tells Parsley via the data-parsley-pattern attribute to test it like a date (in the German notation).
<div class="formInset">
<h2 class="formInset-title">Form title</h2>
<div class="formInset-description">
<p>Cardigan Pinterest gentrify, biodiesel locavore Echo Park bespoke tattooed mlkshk. Master cleanse actually XOXO Schlitz. Four loko disrupt jean shorts meh, normcore vegan tilde vinyl small batch organic Marfa migas Austin Schlitz. Bitters sartorial gastropub, hashtag four loko skateboard chillwave deep.</p>
</div>
<form class="formInset-form formValidator" method="POST" action="./" accept-charset="UTF-8" data-parsley-validate data-parsley-trigger="input focusout">
<fieldset class="formFieldset">
<div class="formFieldset-fields">
<div class="formFieldset-field">
<div class="formField is-required" data-validate="true">
<label class="label is-required" for="field-text">Text</label>
<span class="formField-field">
<input class="field" type="text" id="field-text" name="text" placeholder="" spellcheck="false" required="" aria-required="true" />
</span>
</div>
</div>
<div class="formFieldset-field">
<div class="formField is-email is-required" data-validate="true">
<label class="label is-required" for="field-email">Email Address</label>
<span class="formField-field">
<input class="field" type="email" id="field-email" name="email" placeholder="" spellcheck="false" required="" aria-required="true" data-parsley-trigger="focusout" />
</span>
</div>
</div>
<div class="formFieldset-field">
<div class="formField is-tel is-required" data-validate="true">
<label class="label is-required" for="field-tel">Phone Number</label>
<span class="formField-field">
<input class="field" type="tel" id="field-tel" name="tel" placeholder="" spellcheck="false" required="" aria-required="true" data-parsley-trigger="focusout" />
</span>
<div class="formMessage js-formValidator-message">
The phone number must be formatted with the national code, for example +49 123456789 or 0049 123456789.
</div>
</div>
</div>
<div class="formFieldset-field">
<div class="formField is-number is-required" data-validate="true">
<label class="label is-required" for="field-number">Number</label>
<span class="formField-field">
<input class="field" type="number" id="field-number" name="number" placeholder="" minlength="3" maxlength="5" spellcheck="false" required="" aria-required="true" data-parsley-validation-threshold="2" />
</span>
<div class="formMessage js-formValidator-message">
The number must be between 3 and 5 digits long.
</div>
</div>
</div>
<div class="formFieldset-field">
<div class="formField is-number is-required" data-validate="true">
<label class="label is-required" for="field-postcode">Postcode</label>
<span class="formField-field">
<input class="field" type="number" id="field-postcode" name="postcode" placeholder="" pattern="\d{5}" spellcheck="false" required="" aria-required="true" data-parsley-error-message="The postcode must be exactly 5 digits long." data-parsley-validation-threshold="4" />
</span>
</div>
</div>
<div class="formFieldset-field">
<div class="formField is-date is-required" data-validate="true">
<label class="label is-required" for="field-date">Date</label>
<span class="formField-field">
<input class="field" type="date" id="field-date" name="date" placeholder="" spellcheck="false" required="" aria-required="true" />
</span>
<div class="formMessage js-formValidator-message">
Ich bin ein Hinweis.
</div>
</div>
</div>
<div class="formFieldset-field">
<div class="formTextarea is-required" data-validate="true">
<label class="label is-required" for="field-message">Your Message</label>
<textarea class="formTextarea-field" id="field-message" name="message" placeholder="Aufforderung Nachricht zu schreiben" required=""></textarea>
</div>
</div>
<div class="formFieldset-field">
<div class="formSelect is-required" data-validate="true">
<label class="label is-required" for="field-select">Auswahlliste</label>
<span class="formSelect-input">
<span class="select">
<select id="field-select" name="name" required="">
<option value="" disabled="disabled" selected="selected">Please select</option>
<hr />
<option value="-1">
Show all
</option>
<hr />
<option value="1">
Option 1
</option>
<option value="2">
Option 2
</option>
<option value="3">
Option 3
</option>
<option value="4" disabled="disabled">
Unavailable option
</option>
</select>
</span>
</span>
</div>
</div>
<div class="formFieldset-field">
<div class="formToggle is-checkbox is-required is-small">
<label class="formToggle-label is-required is-small"><span class="toggle is-checkbox is-small">
<input class="toggle-input" role="switch" type="checkbox" name="formtoggle" value="" required="" data-parsley-trigger="change" /><span class="toggle-marker"></span>
</span>
<span>I have read and accept the <a href="" #>privacy policy</a>, the <a href="" #>terms and conditions of participation</a> and the <a href="" #>general terms and conditions</a>.</span></label>
</div>
</div>
<div class="formFieldset-field">
<fieldset class="formToggleSet is-required" data-validate="true">
<legend class="formToggleSet-label">Group of Checkboxes</legend>
<div class="formToggleSet-options">
<div class="formToggleSet-option">
<div class="formToggle is-checkbox is-required">
<label class="formToggle-label is-required"><span class="toggle is-checkbox">
<input class="toggle-input" role="switch" type="checkbox" name="checkbox-group[]" value="1" required="" data-parsley-trigger="change" data-parsley-mincheck="2" /><span class="toggle-marker"></span>
</span>
<span>Option 1</span></label>
</div>
</div>
<div class="formToggleSet-option">
<div class="formToggle is-checkbox is-required">
<label class="formToggle-label is-required"><span class="toggle is-checkbox">
<input class="toggle-input" role="switch" type="checkbox" name="checkbox-group[]" value="2" required="" data-parsley-trigger="change" /><span class="toggle-marker"></span>
</span>
<span>Option 2</span></label>
</div>
</div>
<div class="formToggleSet-option">
<div class="formToggle is-checkbox is-required">
<label class="formToggle-label is-required"><span class="toggle is-checkbox">
<input class="toggle-input" role="switch" type="checkbox" name="checkbox-group[]" value="3" required="" data-parsley-trigger="change" /><span class="toggle-marker"></span>
</span>
<span>Option 3</span></label>
</div>
</div>
</div>
<div class="formMessage js-formValidator-message">
At least two options must be selected.
</div>
</fieldset>
</div>
<div class="formFieldset-field">
<fieldset class="formToggleSet is-required" data-validate="true">
<legend class="formToggleSet-label">Group of radio buttons</legend>
<div class="formToggleSet-options">
<div class="formToggleSet-option">
<div class="formToggle is-radio is-required">
<label class="formToggle-label is-required"><span class="toggle is-radio">
<input class="toggle-input" role="switch" type="radio" name="radio-group[]" value="1" required="" data-parsley-trigger="change" /><span class="toggle-marker"></span>
</span>
<span>Option 1</span></label>
</div>
</div>
<div class="formToggleSet-option">
<div class="formToggle is-radio is-required">
<label class="formToggle-label is-required"><span class="toggle is-radio">
<input class="toggle-input" role="switch" type="radio" name="radio-group[]" value="2" required="" data-parsley-trigger="change" /><span class="toggle-marker"></span>
</span>
<span>Option 2</span></label>
</div>
</div>
<div class="formToggleSet-option">
<div class="formToggle is-radio is-required">
<label class="formToggle-label is-required"><span class="toggle is-radio">
<input class="toggle-input" role="switch" type="radio" name="radio-group[]" value="3" required="" data-parsley-trigger="change" /><span class="toggle-marker"></span>
</span>
<span>Option 3</span></label>
</div>
</div>
</div>
<div class="formMessage js-formValidator-message">
One option must be selected.
</div>
</fieldset>
</div>
</div>
</fieldset>
<div class="buttonGroup">
<button class="button is-secondary"><span class="button-label">Back</span></button>
<button class="button" type="submit"><span class="button-label">Send</span></button>
</div>
</form>
</div>
<div class="formInset{{#modifier}} {{.}}{{/modifier}}">
{{#title}}
<h2 class="formInset-title">{{{.}}}</h2>
{{/title}}
{{#if description}}
<div class="formInset-description"{{#theme}} data-theme="{{.}}"{{/theme}}>
{{{description}}}
{{#figure}}
{{render '@figure' (contextData '@forminset' this) merge=true}}
{{/figure}}
{{#documentmockup}}
{{render '@documentmockup' (contextData '@forminset' this) merge=true}}
{{/documentmockup}}
</div>
{{/if}}
<form class="formInset-form{{#if validate}} formValidator{{/if}}" method="{{#method}}{{.}}{{/method}}{{^method}}POST{{/method}}" action="{{#action}}{{.}}{{/action}}{{^action}}./{{/action}}" accept-charset="UTF-8" {{#if validate}} data-parsley-validate data-parsley-trigger="input focusout"{{/if}}>
{{#formfield}}
<!-- Only for demonstration non-compliant markup -->
{{render '@formfield' (contextData '@forminset' this) merge=false}}
{{/formfield}}
{{#formhidden}}
<div>
<!-- Only for demonstration non-compliant markup -->
{{render '@formhidden' (contextData '@forminset' this) merge=false}}
</div>
{{/formhidden}}
{{#formfieldsets}}
{{render '@formfieldset' (contextData '@forminset' this) merge=false}}
{{/formfieldsets}}
{{#buttongroup}}
{{render '@buttongroup' (contextData '@forminset' this) merge=false}}
{{/buttongroup}}
</form>
</div>
{
"title": "Form title",
"description": "<p>Cardigan Pinterest gentrify, biodiesel locavore Echo Park bespoke tattooed mlkshk. Master cleanse actually XOXO Schlitz. Four loko disrupt jean shorts meh, normcore vegan tilde vinyl small batch organic Marfa migas Austin Schlitz. Bitters sartorial gastropub, hashtag four loko skateboard chillwave deep.</p>\n",
"formfieldsets": [
{
"buttongroup": null,
"fields": [
{
"formfield": {
"is-text": true,
"is-required": true,
"validate": true,
"id": "text",
"name": "text",
"label": "Text",
"placeholder": "Simple text",
"message": null
}
},
{
"formfield": {
"is-text": true,
"is-required": true,
"validate": true,
"type": "email",
"id": "email",
"name": "email",
"label": "Email Address",
"parsley": {
"trigger": "focusout"
},
"message": null
}
},
{
"formfield": {
"is-text": true,
"is-required": true,
"validate": true,
"type": "tel",
"id": "tel",
"name": "tel",
"label": "Phone Number",
"parsley": {
"trigger": "focusout"
},
"message": {
"content": "The phone number must be formatted with the national code, for example +49 123456789 or 0049 123456789."
}
}
},
{
"formfield": {
"is-text": true,
"is-required": true,
"validate": true,
"type": "number",
"id": "number",
"name": "number",
"label": "Number",
"minlength": 3,
"maxlength": 5,
"parsley": {
"threshold": 2
},
"message": {
"content": "The number must be between 3 and 5 digits long."
}
}
},
{
"formfield": {
"is-text": true,
"is-required": true,
"validate": true,
"type": "number",
"id": "postcode",
"name": "postcode",
"label": "Postcode",
"pattern": "\\d{5}",
"parsley": {
"threshold": 4,
"error-message": "The postcode must be exactly 5 digits long."
},
"message": null
}
},
{
"formfield": {
"is-text": true,
"is-required": true,
"validate": true,
"type": "date",
"id": "date",
"name": "date",
"label": "Date"
}
},
{
"formtextarea": {
"is-required": true,
"validate": true,
"id": "message",
"name": "message",
"label": "Your Message",
"message": null
}
},
{
"formselect": {
"is-required": true,
"validate": true,
"id": "select",
"name": "name",
"placeholder": "Please select",
"message": null,
"options": [
{
"label": null
},
{
"label": "Show all",
"value": -1
},
{
"label": null
},
{
"label": "Option 1",
"value": 1
},
{
"label": "Option 2",
"value": 2
},
{
"label": "Option 3",
"value": 3
},
{
"label": "Unavailable option",
"value": 4,
"is-disabled": true
}
]
}
},
{
"formtoggle": {
"is-required": true,
"modifier": "is-small",
"name": "formtoggle",
"label": "I have read and accept the <a href=\"\"#>privacy policy</a>, the <a href=\"\"#>terms and conditions of participation</a> and the <a href=\"\"#>general terms and conditions</a>."
}
},
{
"formtoggleset": {
"is-toggle-group": true,
"is-required": true,
"validate": true,
"type": "checkbox-group",
"name": "checkbox-group",
"label": "Group of Checkboxes",
"options": [
{
"is-required": true,
"type": "checkbox",
"id": "checkbox-group-option-1",
"name": "checkbox-group[]",
"label": "Option 1",
"value": 1,
"parsley": {
"mincheck": 2
}
},
{
"is-required": true,
"type": "checkbox",
"id": "checkbox-group-option-2",
"name": "checkbox-group[]",
"label": "Option 2",
"value": 2
},
{
"is-required": true,
"type": "checkbox",
"id": "checkbox-group-option-3",
"name": "checkbox-group[]",
"label": "Option 3",
"value": 3
}
],
"message": {
"content": "At least two options must be selected."
}
}
},
{
"formtoggleset": {
"is-toggle-group": true,
"is-required": true,
"validate": true,
"type": "radio-group",
"name": "radio-group",
"label": "Group of radio buttons",
"options": [
{
"is-required": true,
"type": "radio",
"id": "radio-group-option-1",
"name": "radio-group[]",
"label": "Option 1",
"value": 1
},
{
"is-required": true,
"type": "radio",
"id": "radio-group-option-2",
"name": "radio-group[]",
"label": "Option 2",
"value": 2
},
{
"is-required": true,
"type": "radio",
"id": "radio-group-option-3",
"name": "radio-group[]",
"label": "Option 3",
"value": 3
}
],
"message": {
"content": "One option must be selected."
}
}
}
]
}
],
"buttongroup": {
"buttons": [
{
"label": "Back",
"modifier": "is-secondary"
},
{
"type": "submit",
"label": "Send"
}
]
},
"validate": true
}
import formValidator from "./_formInset.script";
function addBusinessEmailValidator() {
function init(data) {
/*
* data {object}: Contains an array "list" with the blacklisted domains.
* If the top level domain is an asterisk, all possible top levels are filtered.
* {
* list: [
* "gmx.de",
* "gmail.*"
* ]
* }
*/
if (typeof data !== "object" || typeof data.list !== "object" || ! data.list.length) {
console.warn("formInset: No definition for business email is found.")
}
const domainsBlacklist = data.list;
window.Parsley.addValidator('businessEmail', {
validateString: function(value) {
const emailChunks = value.split('@');
if (emailChunks.length < 2) {
return true;
}
const domain = emailChunks[1].toLowerCase();
if (domain === "") {
return true;
}
const domainWithoutTopLevel = domain.replace(/\.[^.]+$/, ".*");
return ! domainsBlacklist.includes(domain) && ! domainsBlacklist.includes(domainWithoutTopLevel);
},
messages: {
en: 'Only business email addresses are accepted.',
de: 'Es werden nur geschäftliche E-Mail-Adressen akzeptiert.',
pl: 'Akceptujemy tylko firmowe adresy e-mail.',
},
});
}
fetch('/domainsBlacklist.json')
.then(response => response.json())
.then(data => {
init(data);
})
.catch(error => console.error('formInset: Can’t load JSON with definitions for business email.', error));
}
/**
* Telephone number validator for Parsley.js
*
* Regex: /^(\+?\d{2,4}\s?)?[\d\s]{8,20}$/
* Accepts: +49 894238438290, 0049 980502389, 04584 539894385, 894238438290
*/
window.Parsley.addValidator('telephone', {
validateString: function (value, requirement, instance) {
// Empty field is allowed (optional)
if (!value || value.trim() === '') {
return true;
}
// Regex: /^(\+?\d{2,4}\s?)?[\d\s]{8,20}$/
// Accepts: +49 894238438290, 0049 980502389, 04584 539894385, 894238438290
const phoneRegex = /^(\+?\d{2,4}\s?)?[\d\s]{8,20}$/,
isValid = phoneRegex.test(value.trim());
return isValid;
},
});
/**
* Automatically attach telephone validation to all input[type="tel"]
*/
function addTelephoneValidation() {
const telInputs = document.querySelectorAll('input[type="tel"]');
telInputs.forEach( input => {
input.setAttribute('data-parsley-telephone', 'true');
input.setAttribute('data-parsley-trigger', 'input focusout');
input.setAttribute('data-parsley-validation-threshold', '8');
});
}
/**
* Init
*/
addTelephoneValidation();
addBusinessEmailValidator();
formValidator.init({
lang: "en",
});
export default (function (){
var defaults = {
lang: "de",
selectors: {
forms: "form[data-parsley-validate]",
fieldContainer: '*[data-validate="true"]',
},
submit: {
selector: "",
disable: true,
},
};
var init = function(options){
var forms = $(defaults.selectors.forms);
if (forms.length === 0){
return;
}
const settings = Object.assign({}, defaults, options);
addValidators();
fixIEDateInput();
forms.each(function(){
new Validator(this, settings);
});
};
var Validator = function(form, settings){
var self = this;
this.settings = $.extend(true, {}, settings);
this.form = $(form);
this.submit = $('button[type="submit"]', this.form);
if (! $.isFunction($.fn.parsley)){
return;
}
this.form.parsley({
excluded: "input[type=button], input[type=submit], input[type=reset], input[type=hidden], [disabled]",
errorClass: "",
successClass: "",
errorsWrapper: '<ul class="parsley-errors-list"></ul>',
errorsContainer: function (field) { return getContainer(field) },
lang: this.settings.lang,
}).on("field:validated", function(formField){
self.updateStatus(self.form.parsley().isValid());
}).on("field:success", function(formField){
self.setSuccessStatus(formField);
}).on("field:error", function(formField){
self.setSuccessStatus(formField, false);
});
// Set language
if ( $("html").attr("lang") ){
var locale = $("html").attr("lang") || defaults.lang;
var matches = locale.match(/^[a-zA-Z]{2}/),
lang = matches[0] || this.settings.lang;
try {
window.Parsley.setLocale(lang);
} catch (e) {
console.log("formValidator: The set language is not available.");
}
}
this.updateStatus(false);
};
function getContainer(field){
var element = field.$element;
if (! element.hasClass(defaults.selectors.fieldContainer)){
return element.closest(defaults.selectors.fieldContainer);
}
return;
}
Validator.prototype.updateStatus = function(status){
this.form[0].dataset.valid = status;
}
Validator.prototype.getParent = function(element){
return element.parents(this.settings.selectors.fieldContainer);
}
Validator.prototype.setSuccessStatus = function(formField, valid){
if (typeof valid !== "boolean") {
valid = true;
}
formField.$element.attr("aria-invalid", ! valid);
const parent = formField.$element.parents(this.settings.selectors.fieldContainer);
parent.attr("data-invalid", ! valid);
const siblings = formField.$element.siblings();
siblings.attr("data-invalid", ! valid);
}
Validator.prototype.updateUI = function(refresh) {
};
Validator.prototype.validate = function(refresh) {
this.form.parsley().validate();
return this.form.parsley().isValid();
};
Validator.prototype.submit = function(callback){
var callback = (typeof callback === "function") ? callback : function(){};
if (! $.isFunction($.fn.parsley)){
callback();
return true;
}
var isValid = this.validate();
if (isValid){
callback();
}
return isValid;
};
var addValidators = function(){
window.Parsley.addValidator('maxFileSize', {
validateString: function(_value, maxSize, parsleyInstance) {
if (! window.FormData) {
return true;
}
var files = parsleyInstance.$element[0].files;
return files.length != 1 || files[0].size <= maxSize * 1024;
},
requirementType: 'integer',
messages: {
en: 'This file should not be larger than %s Kb.',
de: 'Die Datei darf nicht größer als %s KB sein.',
}
});
window.Parsley.addValidator('fileTypes', {
validateString: function(_value, types, parsleyInstance) {
if (! window.FormData || ! types) {
return true;
}
var types = types.split(/, ?/);
var files = parsleyInstance.$element[0].files;
return files.length != 1 || types.indexOf(files[0].type) !== -1;
},
requirementType: 'string',
messages: {
en: 'This file is not the right type.',
de: 'Die Datei ist vom falschen Typ.',
}
});
};
var fixIEDateInput = function(input){
function getInternetExplorerVersion(){
var rV = -1; // Return value assumes failure.
if (navigator.appName == 'Microsoft Internet Explorer' || navigator.appName == 'Netscape') {
var uA = navigator.userAgent;
var rE = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");
if (rE.exec(uA) != null) {
rV = parseFloat(RegExp.$1);
}
else if (!!navigator.userAgent.match(/Trident.*rv\:11\./)) {
rV = 11;
}
}
return rV;
}
if (getInternetExplorerVersion() === -1){
return;
}
$('input[type="date"]').each(function(){
var input = $(this);
// Please regard: Pattern does not check if date exists,
// so eg. `31.02.2000` will be valid
var pattern = "([0-2][1-9]|3[0-1])\\.(0[1-9]|1[0-2])\\.(19|20)\\d{2}";
input.attr("type", "text")
.attr("data-parsley-pattern", pattern)
.attr("data-parsley-validation-threshold", "10");
});
}
return {
init: init
};
})();
@import "_formInset.settings";
@import "_formInset.styles";
%formInset {
.fileCard {
background-color: $_page-color;
}
.buttonGroup {
@include stack-spacing(large);
}
&-title + &-description {
@include stack-spacing(component);
text-align: center;
}
&-description {
> .figure {
@include stack-spacing(large);
}
}
.documentMockup {
@include stack-spacing(large);
background-color: $_BACKDROP-COLOR;
}
&-form {
box-shadow: none;
.buttonGroup {
@include stack-spacing(component);
}
}
&-title ~ &-form > .buttonGroup {
justify-content: center;
}
@include only-on-desktop(){
width: get-columns-width(8);
margin-left: auto;
margin-right: auto;
}
}
%formInset--side-by-side {
width: 100%;
.buttonGroup {
justify-content: flex-start;
}
%formInset-description {
text-align: left !important;
}
%formInset-description[data-theme] {
padding: var(--bp);
}
@include only-on-desktop(){
display: grid;
column-gap: var(--gg);
row-gap: var(--sp-component);
grid-template-columns: 1fr 1fr;
.formFieldset {
@include stack-spacing(0);
}
.formFieldset + .formFieldset {
padding-top: 0;
}
%formInset-title {
grid-column: 1 / span 2;
}
%formInset-description {
@include stack-spacing(0);
grid-column: 1 / span 1;
}
%formInset-form {
@include stack-spacing(0);
grid-column: 2 / span 1;
height: 100%;
border-radius: 0 var(--br) var(--br) 0;
padding: var(--bp);
background-color: $card_background-color;
display: flex;
flex-direction: column;
.formFieldset {
padding: 0;
}
.formFieldset:only-child {
height: 100%;
}
> *:last-child:not(:only-child),
.formFieldset > .buttonGroup:last-child {
flex-grow: 1;
align-items: flex-end;
}
> .buttonGroup {
@include stack-spacing(0);
padding: $formFieldset_stack-spacing 0 0;
}
}
%formInset-description[data-theme] {
padding: var(--bp-large);
margin-right: calc(-.5 * var(--gg));
border-top-left-radius: var(--br);
border-bottom-left-radius: var(--br);
}
%formInset-description[data-theme] + %formInset-form {
margin-left: calc(-.5 * var(--gg));
padding: var(--bp-large);
.formFieldset + .buttonGroup {
padding-top: $formFieldset_stack-spacing;
}
}
}
}
.formInset.is-side-by-side {
@extend %formInset--side-by-side;
}
// Highlighting non-compliant markup
.formInset-form:has(> *[class^="form"]:not(.formFieldset)) {
@extend %_not-compliant;
}
$formInset_button_style--invalid: (
) !default;
%formInset {
@include stack-spacing(section);
&-title {
@extend %sectionTitle;
@include stack-spacing(0);
}
&-description {
@extend %richtextBlock;
&:not(:first-child) {
@include stack-spacing();
}
> *:first-child {
@include stack-spacing(0);
}
}
&-form {
@include stack-spacing(0);
&:not(:first-child) {
@include stack-spacing(component);
}
.buttonGroup {
@include stack-spacing();
justify-content: flex-end;
}
.formFieldset:first-child {
@include stack-spacing(0);
}
}
}
.formInset {
@extend %formInset;
&-title {
@extend %formInset-title;
}
&-description {
@extend %formInset-description;
}
&-form {
@extend %formInset-form;
}
}
//***** Validation *****//
.formInset-form[data-parsley-validate] {
transition-duration: $_transition-duration--out;
*[data-invalid="true"] {
transition: color $_transition-duration--in;
.formMessage {
display: none;
}
}
label {
transition-property: color;
transition-duration: inherit
}
input {
transition-property: border-color;
transition-duration: inherit
}
&[data-valid="false"] .button[type="submit"] {
@include styles($formInset_button_style--invalid);
}
.formToggle-label {
flex-wrap: wrap;
span:not(.toggle) {
flex: 1 1;
}
}
}
.parsley-errors {
&-list {
list-style: none;
padding: 0;
margin-top: 0;
&:empty {
display: none;
}
li {
@extend %formMessage;
}
li + li {
@include stack-spacing(small);
}
.formToggle-label & {
order: 99;
width: 100%;
margin-top: $field_stack-spacing;
}
}
}